├── .github └── issue_template.md ├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── examples ├── MAX30100_Debug │ └── MAX30100_Debug.ino ├── MAX30100_Minimal │ └── MAX30100_Minimal.ino ├── MAX30100_RawData │ └── MAX30100_RawData.ino └── MAX30100_Tester │ └── MAX30100_Tester.ino ├── extras ├── arduino-wiring.pdf ├── block-diagram.png ├── recorder │ ├── README.md │ ├── beat_analysis.ipynb │ ├── recorder.py │ ├── requirements.txt │ ├── sampling_analysis.ipynb │ └── test.out.sample └── rolling_graph │ ├── README.md │ └── rolling_graph.pde ├── library.json ├── library.properties └── src ├── CircularBuffer.h ├── CircularBuffer.tpp ├── MAX30100.cpp ├── MAX30100.h ├── MAX30100_BeatDetector.cpp ├── MAX30100_BeatDetector.h ├── MAX30100_Filters.h ├── MAX30100_PulseOximeter.cpp ├── MAX30100_PulseOximeter.h ├── MAX30100_Registers.h ├── MAX30100_SpO2Calculator.cpp └── MAX30100_SpO2Calculator.h /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ### Troubleshooting checklist 2 | 3 | - [ ] I read the README (on master) thoroughly 4 | - [ ] I ran the MAX30100_Tester and I'm going to paste the output down below 5 | - [ ] I filled in all the details of my setup down below 6 | 7 | ### Description of the issue 8 | 9 | ### Output from MAX30100_Tester example 10 | 11 | ### Details of my setup 12 | 13 | * Arduino hardware: 14 | * MAX30100 breakout: 15 | * Arduino framework version: 16 | * MAX30100 library version: 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | .clang_complete 3 | .gcc-flags.json 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | 5 | sudo: false 6 | cache: 7 | directories: 8 | - "~/.platformio" 9 | 10 | env: 11 | - PLATFORMIO_CI_SRC=examples/MAX30100_Minimal 12 | - PLATFORMIO_CI_SRC=examples/MAX30100_Debug 13 | 14 | install: 15 | - pip install -U platformio 16 | 17 | script: 18 | - platformio ci --lib="." --board=uno 19 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arduino-MAX30100 2 | 3 | [![Build Status](https://travis-ci.org/oxullo/Arduino-MAX30100.svg?branch=master)](https://travis-ci.org/oxullo/Arduino-MAX30100) 4 | 5 | Arduino library for the Maxim Integrated MAX30100 oximetry / heart rate sensor. 6 | 7 | ![MAX30100](http://www.mouser.com/images/microsites/Maxim_MAX30100.jpg) 8 | 9 | ## Disclaimer 10 | 11 | The library is offered only for educational purposes and it is not meant for medical uses. 12 | Use it at your sole risk. 13 | 14 | ## Notes 15 | 16 | Maxim integrated stopped the production of the MAX30100 in favor of MAX30101 and MAX30102. 17 | Therefore this library won't be seeing any further improvement, besides fixes. 18 | 19 | *IMPORTANT: when submitting issues, make sure to fill ALL the fields indicated in the template text of the issue. The issue will be marked as invalid and closed immediately otherwise.* 20 | 21 | ## Hardware 22 | 23 | This library has been tested with the MikroElektronika Heart rate click daughterboard: 24 | 25 | http://www.mikroe.com/click/heart-rate/ 26 | 27 | along with an Arduino UNO r3. Any Arduino supporting the Wire library should work. 28 | 29 | The only required connection to the sensor is the I2C bus (SDA, SCL lines, pulled up). 30 | 31 | An example which shows a possible way to wire up the sensor is shown in 32 | [extras/arduino-wiring.pdf](extras/arduino-wiring.pdf) 33 | 34 | Note: The schematics above shows also how to wire up the interrupt line, which is 35 | currently not used by the library. 36 | 37 | ### Pull-ups 38 | 39 | Since the I2C interface is clocked at 400kHz, make sure that the SDA/SCL lines are pulled 40 | up by 4,7kOhm or less resistors. 41 | 42 | ## Architecture 43 | 44 | The library offers a low-level driver class, MAX30100. 45 | This component allows for low level communication with the device. 46 | 47 | A rather simple but working implementation of the heart rate and SpO2 calculation 48 | can be found in the PulseOximeter class. 49 | 50 | This high level class sets up the sensor and data processing pipelines in order to 51 | offer a very simple interface to the data: 52 | 53 | * Sampling frequency set to 100Hz 54 | * 1600uS pulse width, full sampling 16bit dynamic 55 | * IR LED current set to 50mA 56 | * Heart-rate + SpO2 mode 57 | 58 | The PulseOximeter class is not optimised for battery-based projects. 59 | 60 | ## Examples 61 | 62 | The included examples show how to use the PulseOximeter class: 63 | 64 | * MAX30100_Minimal: a minimal example that dumps human-readable results via serial 65 | * MAX30100_Debug: used in conjunction with the Processing pde "rolling_graph" (extras folder), to show the sampled data at various processing stages 66 | * MAX30100_RawData: demonstrates how to access raw data from the sensor 67 | * MAX30100_Tester: this sketch helps to find out potential issues with the sensor 68 | 69 | ## Troubleshooting 70 | 71 | Run the MAX30100_Tester example to inspect the state of your rig. 72 | When run with a properly connected sensor, it should print: 73 | 74 | ``` 75 | Initializing MAX30100..Success 76 | Enabling HR/SPO2 mode..done. 77 | Configuring LEDs biases to 50mA..done. 78 | Lowering the current to 7.6mA..done. 79 | Shutting down..done. 80 | Resuming normal operation..done. 81 | Sampling die temperature..done, temp=24.94C 82 | All test pass. Press any key to go into sampling loop mode 83 | ``` 84 | 85 | Pressing any key, a data stream with the raw values from the photodiode sampling red 86 | and infrared is presented. 87 | With no finger on the sensor, both values should be close to zero and jump up when 88 | a finger is positioned on top of the sensor. 89 | 90 | 91 | Typical issues when attempting to run the examples: 92 | 93 | ### I2C error or garbage data 94 | 95 | In particular when the tester fails with: 96 | 97 | ``` 98 | Initializing MAX30100..FAILED: I2C error 99 | ``` 100 | 101 | This is likely to be caused by an improper pullup setup for the I2C lines. 102 | Make sure to use 4,7kOhm resistors, checking if the breakout board in use is equipped 103 | with pullups. 104 | 105 | ### Logic level compatibility 106 | 107 | If you're using a 5V-based microcontroller but the sensor breakout board pulls SDA and SCL up 108 | to 3.3V, you should ensure that its inputs are compatible with the 3.3V logic levels. 109 | An original Atmel ATMega328p considers anything above 3V as HIGH, so it might work well without 110 | level shifting hardware. 111 | 112 | Since the MAX30100 I2C pins maximum ratings aren't bound to Vdd, a cheap option to avoid 113 | level shifting is to simply pull SDA and SCL up to 5V instead of 3.3V. 114 | 115 | ### Sketchy beat frequency readouts 116 | 117 | The beat detector uses the IR LED to track the heartbeat. The IR LED is biased 118 | by default at 50mA on all examples, excluding the Tester (which sets it to 7.6mA). 119 | This value is somehow critical and it must be experimented with. 120 | 121 | The current can be adjusted using PulseOximeter::setIRLedCurrent(). 122 | Check the _MAX30100_Minimal_ example. 123 | 124 | ### Advanced debugging 125 | 126 | Two tools are available for further inspection and error reporting: 127 | 128 | * extras/recorder: a python script that records a session that can be then analysed with the provided collection of jupyter notebooks 129 | * extras/rolling_graph: to be used in conjunction with _MAX30100_Debug_ example, it provides a visual feedback of the LED tracking and heartbeat detector 130 | 131 | Both tools have additional information on the README.md in their respective directories. 132 | 133 | ## Tested devices 134 | 135 | * Arduino UNO r3, Mikroelektronika Heart rate click (https://shop.mikroe.com/heart-rate-click) 136 | 137 | This combination works without level shifting devices at 400kHz I2C clock rate. 138 | 139 | * Arduino UNO r3, MAX30100 custom board with 4.7kOhm pullups to 5V to SDA, SCL, INT 140 | 141 | As above, working at 400kHz 142 | 143 | * Sparkfun Arduino Pro 328p 8MHz 3.3V, Mikroelektronika Heart rate click 144 | 145 | Even if this combination works (MAX30100 communication), the slower clock speed fails to deliver 146 | the required performance deadlines for a 100Hz sampling. 147 | 148 | ## Troubled breakouts 149 | 150 | This breakout board: http://www.sunrom.com/m/5337 151 | 152 | Has pullups on the Vdd (1.8V) line. To make it work, the three 4k7 pullups must be 153 | desoldered and external 4.7k pullups to Vcc of the MCU must be added. 154 | -------------------------------------------------------------------------------- /examples/MAX30100_Debug/MAX30100_Debug.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | // This example must be used in conjunction with the Processing sketch located 20 | // in extras/rolling_graph 21 | 22 | #include 23 | #include "MAX30100_PulseOximeter.h" 24 | 25 | #define REPORTING_PERIOD_MS 1000 26 | 27 | // PulseOximeter is the higher level interface to the sensor 28 | // it offers: 29 | // * beat detection reporting 30 | // * heart rate calculation 31 | // * SpO2 (oxidation level) calculation 32 | PulseOximeter pox; 33 | 34 | uint32_t tsLastReport = 0; 35 | 36 | // Callback (registered below) fired when a pulse is detected 37 | void onBeatDetected() 38 | { 39 | Serial.println("B:1"); 40 | } 41 | 42 | void setup() 43 | { 44 | Serial.begin(115200); 45 | 46 | // Initialize the PulseOximeter instance and register a beat-detected callback 47 | // The parameter passed to the begin() method changes the samples flow that 48 | // the library spews to the serial. 49 | // Options: 50 | // * PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT : filtered samples and beat detection threshold 51 | // * PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES : sampled values coming from the sensor, with no processing 52 | // * PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES : sampled values after the DC removal filter 53 | 54 | // Initialize the PulseOximeter instance 55 | // Failures are generally due to an improper I2C wiring, missing power supply 56 | // or wrong target chip 57 | if (!pox.begin(PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT)) { 58 | Serial.println("ERROR: Failed to initialize pulse oximeter"); 59 | for(;;); 60 | } 61 | 62 | pox.setOnBeatDetectedCallback(onBeatDetected); 63 | } 64 | 65 | void loop() 66 | { 67 | // Make sure to call update as fast as possible 68 | pox.update(); 69 | 70 | // Asynchronously dump heart rate and oxidation levels to the serial 71 | // For both, a value of 0 means "invalid" 72 | if (millis() - tsLastReport > REPORTING_PERIOD_MS) { 73 | Serial.print("H:"); 74 | Serial.println(pox.getHeartRate()); 75 | 76 | Serial.print("O:"); 77 | Serial.println(pox.getSpO2()); 78 | 79 | tsLastReport = millis(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /examples/MAX30100_Minimal/MAX30100_Minimal.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | #include "MAX30100_PulseOximeter.h" 21 | 22 | #define REPORTING_PERIOD_MS 1000 23 | 24 | // PulseOximeter is the higher level interface to the sensor 25 | // it offers: 26 | // * beat detection reporting 27 | // * heart rate calculation 28 | // * SpO2 (oxidation level) calculation 29 | PulseOximeter pox; 30 | 31 | uint32_t tsLastReport = 0; 32 | 33 | // Callback (registered below) fired when a pulse is detected 34 | void onBeatDetected() 35 | { 36 | Serial.println("Beat!"); 37 | } 38 | 39 | void setup() 40 | { 41 | Serial.begin(115200); 42 | 43 | Serial.print("Initializing pulse oximeter.."); 44 | 45 | // Initialize the PulseOximeter instance 46 | // Failures are generally due to an improper I2C wiring, missing power supply 47 | // or wrong target chip 48 | if (!pox.begin()) { 49 | Serial.println("FAILED"); 50 | for(;;); 51 | } else { 52 | Serial.println("SUCCESS"); 53 | } 54 | 55 | // The default current for the IR LED is 50mA and it could be changed 56 | // by uncommenting the following line. Check MAX30100_Registers.h for all the 57 | // available options. 58 | // pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA); 59 | 60 | // Register a callback for the beat detection 61 | pox.setOnBeatDetectedCallback(onBeatDetected); 62 | } 63 | 64 | void loop() 65 | { 66 | // Make sure to call update as fast as possible 67 | pox.update(); 68 | 69 | // Asynchronously dump heart rate and oxidation levels to the serial 70 | // For both, a value of 0 means "invalid" 71 | if (millis() - tsLastReport > REPORTING_PERIOD_MS) { 72 | Serial.print("Heart rate:"); 73 | Serial.print(pox.getHeartRate()); 74 | Serial.print("bpm / SpO2:"); 75 | Serial.print(pox.getSpO2()); 76 | Serial.println("%"); 77 | 78 | tsLastReport = millis(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/MAX30100_RawData/MAX30100_RawData.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | // The example shows how to retrieve raw values from the sensor 20 | // experimenting with the most relevant configuration parameters. 21 | // Use the "Serial Plotter" app from arduino IDE 1.6.7+ to plot the output 22 | 23 | #include 24 | #include "MAX30100.h" 25 | 26 | // Sampling is tightly related to the dynamic range of the ADC. 27 | // refer to the datasheet for further info 28 | #define SAMPLING_RATE MAX30100_SAMPRATE_100HZ 29 | 30 | // The LEDs currents must be set to a level that avoids clipping and maximises the 31 | // dynamic range 32 | #define IR_LED_CURRENT MAX30100_LED_CURR_50MA 33 | #define RED_LED_CURRENT MAX30100_LED_CURR_27_1MA 34 | 35 | // The pulse width of the LEDs driving determines the resolution of 36 | // the ADC (which is a Sigma-Delta). 37 | // set HIGHRES_MODE to true only when setting PULSE_WIDTH to MAX30100_SPC_PW_1600US_16BITS 38 | #define PULSE_WIDTH MAX30100_SPC_PW_1600US_16BITS 39 | #define HIGHRES_MODE true 40 | 41 | 42 | // Instantiate a MAX30100 sensor class 43 | MAX30100 sensor; 44 | 45 | void setup() 46 | { 47 | Serial.begin(115200); 48 | 49 | Serial.print("Initializing MAX30100.."); 50 | 51 | // Initialize the sensor 52 | // Failures are generally due to an improper I2C wiring, missing power supply 53 | // or wrong target chip 54 | if (!sensor.begin()) { 55 | Serial.println("FAILED"); 56 | for(;;); 57 | } else { 58 | Serial.println("SUCCESS"); 59 | } 60 | 61 | // Set up the wanted parameters 62 | sensor.setMode(MAX30100_MODE_SPO2_HR); 63 | sensor.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT); 64 | sensor.setLedsPulseWidth(PULSE_WIDTH); 65 | sensor.setSamplingRate(SAMPLING_RATE); 66 | sensor.setHighresModeEnabled(HIGHRES_MODE); 67 | } 68 | 69 | void loop() 70 | { 71 | uint16_t ir, red; 72 | 73 | sensor.update(); 74 | 75 | while (sensor.getRawValues(&ir, &red)) { 76 | Serial.print(ir); 77 | Serial.print('\t'); 78 | Serial.println(red); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/MAX30100_Tester/MAX30100_Tester.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2017 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | // This example can be used to test connectivity and operation of the sensor 20 | // check the README file on the repo's root for a troubleshooting guide in case 21 | // any of the tests running fail 22 | 23 | #include 24 | #include "MAX30100.h" 25 | 26 | MAX30100 sensor; 27 | 28 | void setup() 29 | { 30 | Serial.begin(115200); 31 | 32 | Serial.print("Initializing MAX30100.."); 33 | 34 | if (!sensor.begin()) { 35 | Serial.print("FAILED: "); 36 | 37 | uint8_t partId = sensor.getPartId(); 38 | if (partId == 0xff) { 39 | Serial.println("I2C error"); 40 | } else { 41 | Serial.print("wrong part ID 0x"); 42 | Serial.print(partId, HEX); 43 | Serial.print(" (expected: 0x"); 44 | Serial.println(EXPECTED_PART_ID, HEX); 45 | } 46 | // Stop here 47 | for(;;); 48 | } else { 49 | Serial.println("Success"); 50 | } 51 | 52 | Serial.print("Enabling HR/SPO2 mode.."); 53 | sensor.setMode(MAX30100_MODE_SPO2_HR); 54 | Serial.println("done."); 55 | 56 | Serial.print("Configuring LEDs biases to 50mA.."); 57 | sensor.setLedsCurrent(MAX30100_LED_CURR_50MA, MAX30100_LED_CURR_50MA); 58 | Serial.println("done."); 59 | 60 | delay(1000); 61 | 62 | Serial.print("Lowering the current to 7.6mA.."); 63 | sensor.setLedsCurrent(MAX30100_LED_CURR_7_6MA, MAX30100_LED_CURR_7_6MA); 64 | Serial.println("done."); 65 | 66 | delay(1000); 67 | 68 | Serial.print("Shutting down.."); 69 | sensor.shutdown(); 70 | Serial.println("done."); 71 | 72 | delay(1000); 73 | 74 | Serial.print("Resuming normal operation.."); 75 | sensor.resume(); 76 | delay(500); 77 | Serial.println("done."); 78 | 79 | uint32_t tsTempSampStart = millis(); 80 | Serial.print("Sampling die temperature.."); 81 | sensor.startTemperatureSampling(); 82 | while(!sensor.isTemperatureReady()) { 83 | if (millis() - tsTempSampStart > 1000) { 84 | Serial.println("ERROR: timeout"); 85 | // Stop here 86 | for(;;); 87 | } 88 | } 89 | 90 | float temperature = sensor.retrieveTemperature(); 91 | Serial.print("done, temp="); 92 | Serial.print(temperature); 93 | Serial.println("C"); 94 | 95 | if (temperature < 5) { 96 | Serial.println("WARNING: Temperature probe reported an odd value"); 97 | } else { 98 | Serial.println("All test pass."); 99 | } 100 | 101 | Serial.println(); 102 | Serial.println("Press any key to go into sampling loop mode"); 103 | while (!Serial.available()); 104 | 105 | sensor.resetFifo(); 106 | } 107 | 108 | void loop() 109 | { 110 | uint16_t ir, red; 111 | 112 | sensor.update(); 113 | 114 | while (sensor.getRawValues(&ir, &red)) { 115 | Serial.print("IR="); 116 | Serial.print(ir); 117 | Serial.print(" RED="); 118 | Serial.println(red); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /extras/arduino-wiring.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxullo/Arduino-MAX30100/5754dfe2cfd882b91d5db748d78c4a6ad4cab0d1/extras/arduino-wiring.pdf -------------------------------------------------------------------------------- /extras/block-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxullo/Arduino-MAX30100/5754dfe2cfd882b91d5db748d78c4a6ad4cab0d1/extras/block-diagram.png -------------------------------------------------------------------------------- /extras/recorder/README.md: -------------------------------------------------------------------------------- 1 | # Session recorder 2 | 3 | This tool pipes a raw session from the sensor into a file for further analysis. 4 | 5 | ## Requirements 6 | 7 | The recorder and the analysis notebook require python and analysis libraries. 8 | Virtualenv is warmly suggested. 9 | 10 | * Flash the example firmware MAX30100_RawData to the microcontroller board 11 | * Install the required libraries 12 | $ virtualenv max30100env 13 | $ source max30100env/bin/activate 14 | $ pip install -Ur requirements.txt 15 | * Ensure the board is connected 16 | 17 | ## Record a session 18 | 19 | Recording a session might be useful as a valuable debugging file when posting issues. 20 | It can be done via command line interface: 21 | 22 | $ ./recorder.py --samples 1000 /dev/ttyACM0 test.out 23 | 24 | the command above records at least 1000 samples of data from the serial device /dev/ttyACM0 to file test.out. 25 | 26 | Each system might expose the microcontroller with different device paths. 27 | 28 | ## Run a beat analysis 29 | 30 | Fire up a jupyter kernel and follow the instruction on the notebook: 31 | 32 | $ jupyter notebook beat_analysis.ipynb 33 | 34 | ## Use the provided sample data 35 | 36 | A sample data file is provided to allow comparisons: test.out.sample 37 | It can be opened from the provided notebooks by either copying it to test.out or by altering 38 | the pd.read_csv() function exposes in each notebook. 39 | 40 | The sample file shows an undisturbed 2000-samples worth of data that exposes an uncompensated 41 | temperature drift. 42 | -------------------------------------------------------------------------------- /extras/recorder/recorder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import print_function 5 | 6 | import time 7 | import threading 8 | import Queue 9 | import argparse 10 | import logging 11 | import serial 12 | 13 | # 14 | # Data logger 15 | # to be used in conjunction with the MAX30100_RawData example 16 | # 17 | 18 | 19 | logger = logging.getLogger(__name__) 20 | 21 | 22 | class SerialStreamer(threading.Thread): 23 | DEFAULT_SPEED = 115200 24 | DEFAULT_HOLDOFF = 3 25 | DEFAULT_TIMEOUT = .1 26 | 27 | def __init__(self, port, holdoff=DEFAULT_HOLDOFF, speed=DEFAULT_SPEED): 28 | super(SerialStreamer, self).__init__() 29 | self._s = serial.Serial(port, speed, timeout=.5) 30 | self._q = Queue.Queue() 31 | self._holdoff = holdoff 32 | self._time_started = 0 33 | 34 | def run(self): 35 | logger.info('Starting streamer thread, delaying acquisition by %.2fs' % self._holdoff) 36 | self._isRunning = True 37 | 38 | tstarted = time.time() 39 | 40 | while time.time() - tstarted < self._holdoff and self._isRunning: 41 | self._s.readline() 42 | 43 | logger.info('Started acquisition') 44 | self._time_started = time.time() 45 | 46 | while self._isRunning: 47 | self._poll() 48 | 49 | def stop(self): 50 | logger.info('Stopping streamer thread') 51 | self._isRunning = False 52 | self.join() 53 | 54 | def get_samples(self): 55 | samples = [] 56 | while not self._q.empty(): 57 | samples.append(self._q.get()) 58 | 59 | return samples 60 | 61 | def _poll(self): 62 | line = self._s.readline().strip() 63 | if line: 64 | spl = line.split('\t') 65 | 66 | if len(spl) != 2: 67 | logger.warning('Ignoring line: %s' % line) 68 | else: 69 | try: 70 | a, b = [int(v) for v in spl] 71 | except Exception, e: 72 | logger.exception(e) 73 | else: 74 | self._q.put((self._get_time_offs(), a, b)) 75 | 76 | def _get_time_offs(self): 77 | return int((time.time() - self._time_started) * 1000.0) 78 | 79 | 80 | def parse_args(): 81 | parser = argparse.ArgumentParser() 82 | parser.add_argument('port', help='Serial port of the device') 83 | parser.add_argument('outfile', help='Output recording file') 84 | parser.add_argument('--holdoff', type=float, default=SerialStreamer.DEFAULT_HOLDOFF, 85 | help='Seconds to wait after connection before starting ' 86 | 'acquisition') 87 | parser.add_argument('--debug', action='store_true', help='Be verbose') 88 | parser.add_argument('--samples', type=int, default=0, 89 | help='Define the number of samples to be fetched, 0 to infinite') 90 | 91 | return parser.parse_args() 92 | 93 | def gather(streamer, fp, maxsamples): 94 | samples_count = 0 95 | 96 | while True: 97 | samples = streamer.get_samples() 98 | samples_count += len(samples) 99 | 100 | for sample in samples: 101 | fp.write('%d\t%d\t%d\n' % sample) 102 | logger.info('Gathered %d/%d/%d samples' % (len(samples), samples_count, maxsamples)) 103 | 104 | if samples_count > maxsamples: 105 | logging.info('Acquired %d samples (requested: %d), stopping' % 106 | (samples_count, maxsamples)) 107 | return 108 | 109 | time.sleep(1) 110 | 111 | def run(port, outfile, holdoff, debug, samples): 112 | 113 | if debug: 114 | level = logging.DEBUG 115 | else: 116 | level = logging.INFO 117 | 118 | logging.basicConfig(level=level) 119 | 120 | streamer = SerialStreamer(port, holdoff) 121 | streamer.start() 122 | 123 | fp = open(outfile, 'w') 124 | 125 | fp.write('timestamp\tir_level\tred_level\n') 126 | 127 | try: 128 | gather(streamer, fp, samples) 129 | except KeyboardInterrupt: 130 | logger.info('Terminating') 131 | finally: 132 | fp.close() 133 | streamer.stop() 134 | 135 | def cli_run(): 136 | args = parse_args() 137 | 138 | run(args.port, args.outfile, args.holdoff, args.debug, args.samples) 139 | 140 | if __name__ == '__main__': 141 | cli_run() 142 | -------------------------------------------------------------------------------- /extras/recorder/requirements.txt: -------------------------------------------------------------------------------- 1 | pyserial 2 | pandas 3 | numpy 4 | scipy 5 | matplotlib 6 | jupyter 7 | -------------------------------------------------------------------------------- /extras/recorder/sampling_analysis.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Sampling time analysis scratchpad\n", 8 | "\n", 9 | "Attempts to analyse the sampling time based on the timestamps associated during acquisition.\n", 10 | "Acquisition timestamps are susceptible to jitter and using the RawData example does not account for filtering overhead." 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": { 17 | "collapsed": true 18 | }, 19 | "outputs": [], 20 | "source": [ 21 | "%matplotlib inline\n", 22 | "from matplotlib import pyplot as plt\n", 23 | "import pandas as pd\n", 24 | "from scipy import signal\n", 25 | "import numpy as np\n", 26 | "import recorder" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "metadata": { 33 | "collapsed": true 34 | }, 35 | "outputs": [], 36 | "source": [ 37 | "%load_ext autoreload\n", 38 | "%autoreload 2" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 3, 44 | "metadata": { 45 | "collapsed": false 46 | }, 47 | "outputs": [ 48 | { 49 | "name": "stderr", 50 | "output_type": "stream", 51 | "text": [ 52 | "INFO:recorder:Starting streamer thread, delaying acquisition by 5.00s\n", 53 | "INFO:recorder:Gathered 0 samples\n", 54 | "INFO:recorder:Gathered 0 samples\n", 55 | "INFO:recorder:Gathered 0 samples\n", 56 | "INFO:recorder:Gathered 0 samples\n", 57 | "INFO:recorder:Gathered 0 samples\n", 58 | "INFO:recorder:Started acquisition\n", 59 | "INFO:recorder:Gathered 1 samples\n", 60 | "INFO:recorder:Gathered 98 samples\n", 61 | "INFO:recorder:Gathered 196 samples\n", 62 | "INFO:recorder:Gathered 294 samples\n", 63 | "INFO:root:Acquired 294 samples (requested: 200), stopping\n", 64 | "INFO:recorder:Stopping streamer thread\n" 65 | ] 66 | } 67 | ], 68 | "source": [ 69 | "# Record 200 samples worth of data, delaying acquisition by 5 seconds\n", 70 | "# this can be done also using the command line interface of recorder.py\n", 71 | "recorder.run(port='/dev/ttyACM0', outfile='test.out', holdoff=5, debug=False, samples=200)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 4, 77 | "metadata": { 78 | "collapsed": true 79 | }, 80 | "outputs": [], 81 | "source": [ 82 | "# Read from the recorded session\n", 83 | "df = pd.read_csv('test.out', delimiter='\\t', index_col=0)" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": 5, 89 | "metadata": { 90 | "collapsed": true 91 | }, 92 | "outputs": [], 93 | "source": [ 94 | "df_ts = pd.DataFrame(df.index)\n", 95 | "df_ts_diffs = df_ts.diff()" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 6, 101 | "metadata": { 102 | "collapsed": false 103 | }, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "" 109 | ] 110 | }, 111 | "execution_count": 6, 112 | "metadata": {}, 113 | "output_type": "execute_result" 114 | }, 115 | { 116 | "data": { 117 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfwAAAFkCAYAAADFZ4k9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJztvXmUZEd17vuLGrpr6u6qVqs1gAYkGYMAy0i60mPGlrHe\nw88gBts0aOErYV/kh4Clt54Bgx9oMLbkCzSYawzmYQP2VYvJgFjmMtiAbBACrLZswAIJ02hWD+qs\nrqG7xoz3R1R0nsrK4QwxZUZ8a/XKrsyTJ86XJ07s+PbesUNIKUlISEhISEjobwz4voCEhISEhIQE\n+0gGPyEhISEhIQIkg5+QkJCQkBABksFPSEhISEiIAMngJyQkJCQkRIBk8BMSEhISEiJAMvgJCQkJ\nCQkRIBn8hISEhISECJAMfkJCQkJCQgRIBj8hISEhISECFDb4QojnCCFuFUI8JISoCyFe1PT5O4QQ\ndwsh5oQQh4UQXxVCXGTukhMSEhISEhKKoozCHwfuAl4HtCrE/+O1z54KPAv4GfAVIcQJJa8xISEh\nISEhoSJElc1zhBB14DIp5a0djtkCHAEukVJ+vXRjCQkJCQkJCaVhNYYvhBgGXgtMA/9ms62EhISE\nhISE9hiycVIhxK8BtwBjwMPAC6SUh9scewJwKcr1v2DjehISEhISEvoUI8CZwJellI91OtCKwQe+\nBpwH7AB+F/iUEOIiKeWhFsdeCvxPS9eRkJCQkJAQA14F3NzpACsGX0p5DPjp2r/vCiHuAV4D3NTi\n8J8B/O3f/i1PfvKTbVxOX+Pb34arr76Gv/qr3Zx3nu+rcY8HHoDLLoPrr4df+7Xy57nmmmvYvXu3\nuQtzhHod/st/gd/9XbjqKn/X4fP3e/GL4WlPgz/6Iy/NG0GV3+91r4P5efjoR81eU6/gT/4EPve5\na/jOd3rv+TWBd7/7bm6++XJYs6WdYEvhN2MA2NzmswWAJz/5yZx//vmOLqd/8NOfAmzjlFPOJ8af\nTwj1un07lfhv27atJ/vfzIx6HR+vxr8qfP5+i4swNOSXf1VU/f1WV3ubfxVs3gz1em8+vyYwMXH8\nv11D4oUNvhBiHDgHWBtqOUsIcR5wGHgMeBtwK/AIyqV/NXAq8KmibSV0x+zs+tfYkPivf40Rs7OJ\nf+z863VYXobhYd9X4x7z8/mPLaPwLwS+jlqDL4F3r73/MeD3gCcBr0YZ+8eA7wHPllLeXaKthC6I\nfcBP/Ne/xoaVFVhYiJc/JIOffQa2b/d7LT5w9Gj+YwsbfCnlbXRezveyoudMKI/YB/zEf/1rbIid\nPzQMvpSNEFdMiN3gz83lPzbV0u9xqBjuruOx3NigeVflv2vXruoX4wGm+FeFr98vFP5VUfb3k1Jx\nX12FY8cMX1SPIPYxsIjCTwa/x6Fmt7uiVTimFF6vGvxQFK6v3y8U/lVR9vdbWFDGHnr/NyiL2MdA\nqy79hLDQLwNeWST+619jg+Y9P68StwY8S5j777+fQ4dalRuxg8OZcmZ33AGnneas6WAwPa1e9+6F\nkRG/12ILO3bs4PTTT2/5me2kvYSAkAb89a+xIfFv/H9uDrZu9Xct999/P09+8pM5WkRyGcRll3lp\nNhi8/vW+r8AexsbGuPvuu1sa/WTwI0Ia8Ne/xobEf/3/fRr8Q4cOcfTo0VRELMEo7r77bi6//HIO\nHTqUDH7s6JekpbJI/NXr4iIsLcGmTX6vxzWy931mBh73OH/XopGKiCW4REraiwhJ4a1/jQ3NCjc2\nxM4/IW4sL6uJfl4kg9/jSAav8Sql32vxgdgNXuz8E+JG0T6fDH6PY3YWtm2Ld7DT/FdX1RKl2KD5\n6//Hhtj5J8SNZPAjQr2ubvipp8Ydwz711Mb/Y0PiHzf/hLiRDH5E0NmZj3tcYx1ybJidbSRqxajw\nEn/YsUNtmhIj/xBw5plncuWVV/q+jCiRDH5E0DdbD/hFair3C5LBS/y3boUtW+Lk7xLf/va3ue66\n65hpcqUMDAwgAi3if+zYMa677jr+6Z/+yfelWEFRr1Yy+D0MPcBpl2ZsA97ysorbx8ofFOdTTmn8\nPzbMzipjnwy+fdx+++1cf/31TOvSdmv48Y9/zF/+5V96uqrOOHr0KNdddx3f+MY3fF+KFSSFHxH0\n7C7WGGbzhCc2/qA4T07C6Gi8/LXBj5G/S8g2y2CGh4cZHBx0fDX50O6a+wXJ4EeEZpd+bAondv5S\nNlzaW7fGxx8Sf1e47rrreNOb3gSomP3AwACDg4Pcd999G2L4H/vYxxgYGOBb3/oWb3jDG9i5cydT\nU1NcddVVrKyscOTIEV796ldzwgknsH37dt785jdvaE9KyXvf+16e+tSnMjo6ysknn8xVV121wbvw\nL//yL1x66aWceOKJjI2NcdZZZ/Ga17wGgPvuu4+dO3cihODaa69lYGCAgYEBrr/+egC+//3vc8UV\nV3D22WczOjrKKaecwmte8xoOZzcogOPfvffee7n88suZnJxk586dvP3tbwfggQce4LLLLmPbtm2c\ncsopvOc971n3/dtuu42BgQE++clP8ta3vpVTTjmFiYkJXvziF/Pggw9Wui+zs8WKbaVKez2M2A2e\n5nvSSWrTlNj4653SYnZpJ5e+G7zsZS/jnnvu4ZZbbuF973sfJ5xwAkIITjzxxLbx+9e//vWccsop\nXH/99dxxxx18+MMfZnJykttvv50zzjiDP/7jP+aLX/wi73rXu3ja057G5Zdffvy7/+2//Tc+/vGP\nc+WVV/LGN76Rffv28f73v5+77rqLb33rWwwODnLw4EEuvfRSdu7cyR/8wR8wOTnJz372M/7u7/4O\ngBNPPJEPfvCDXHXVVbz0pS/lpS99KQC/8Au/AMBXv/pV9u3bx5VXXsnJJ5/MD3/4Qz70oQ/xH//x\nH3z7298+fi2a32/91m9x7rnnctNNN/H3f//3vPOd72T79u186EMf4pJLLuGmm27i5ptv5vd///e5\n6KKLePazn73u93jnO9/JwMAAb3nLWzhw4AC7d+/mBS94AXfddRebN28udV9mZmB8vEDxHSml13/A\n+YC88847ZUIx/M3fSAlSPvCAev3sZ31fkVvcfrvi/f3vS7l1q5TvepfvK3KL/fsV/899TsqnP13K\nq67yfUXusWWLlO9+t5Qvf7mUL3iB32u58847ZT+PZe9617vkwMCAvO+++9a9f+aZZ8orrrji+N8f\n/ehHpRBCvvCFL1x33DOf+Uw5MDAgr7766uPvra6uytNOO03+0i/90vH3/vmf/1kKIeQtt9yy7vtf\n+cpXpBBC7tmzR0op5ec+9zk5MDAg9+7d2/aaDx06JIUQ8rrrrtvw2cLCwob3brnlFjkwMCC/+c1v\nHn/v2muvlUII+Xu/93sbrntwcFC+KzPwTE9Py7GxsXW/xze+8Q0phJCnnXaanJ+fP/7+pz71KSmE\nkO9///vbXr+UnfvVm94k5eMfrz4Hzpdd7G1S+D2MmRkYGlLLkvTfMUHzjTWGGzt/XYdC83/gAd9X\nVAxHj8KPfmS3jSc9CcbG7LbRCkKIDUv1Lr74Yu644w6uuOKK4+8NDAxw4YUXsnfv3uPvffrTn2Zy\ncpJLLrmExx577Pj7T3/605mYmODrX/86r3jFK5icnERKya233srTnvY0hoaKmbOsql5cXGRubo6L\n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\n", 118 | "text/plain": [ 119 | "" 120 | ] 121 | }, 122 | "metadata": {}, 123 | "output_type": "display_data" 124 | } 125 | ], 126 | "source": [ 127 | "df_ts_diffs[10:40].plot()" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": 7, 133 | "metadata": { 134 | "collapsed": false 135 | }, 136 | "outputs": [ 137 | { 138 | "data": { 139 | "text/plain": [ 140 | "array([[]], dtype=object)" 141 | ] 142 | }, 143 | "execution_count": 7, 144 | "metadata": {}, 145 | "output_type": "execute_result" 146 | }, 147 | { 148 | "data": { 149 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAg0AAAFyCAYAAAB2hOkdAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzt3X10XHd95/H3N4SEmjYJEIjLFhOy4SHdlgc5DbhQWEhj\n2lCmsG0xpinUblkebC/rtjZkQ2KbnLbIHEjAdre0GAoLkQMBDJzmJE6ghTrQsEg8tGClCzgVJCQg\n8gQRARr/9o97BeORxv5J1tw7o/t+nTPH1p07o+/9yJY+unPn3kgpIUmSdDTH1T2AJEkaDJYGSZKU\nxdIgSZKyWBokSVIWS4MkScpiaZAkSVksDZIkKYulQZIkZbE0SJKkLJYGacBExM0R8c6655DUPJYG\nqU9FxIqI2BIRJ3XcdQjoy/O/R8TPlDM/s+5ZJC284+seQFJXvwpcArwLuKdt+eMpikM/WgJsoSg1\nn6p5FkkLzNIg9a+YbWFK6cdVDzIHs84saXHw5QmpD0XEFmB7+eHNEXEoIu6PiEd3HtMQES8r7396\nRLwtIr4dEXdGxF9HxPERcXJEvCcivhsRd0TE8CyfLyLif0bEv0bEDyLitvLxp3Ssd3ZEXBsR34mI\nqYj4ekTsLu97NPBtir0MW8uZDkXEJeX9vxwR74qIr5Wf41sRsTsiHtrxOaYf+9iIeG9E3FVu0xvK\n+x8VEXsj4u7yOf6k4/HPKh//ooj4i3Kd70fERyLiF475iyM1mHsapP70QeBxwIuB1wDfpfhh/B26\nH8+wA/gWxUsaTwNeDtxF8TLHvwP/Czgf+LOI+JeU0nvbHvs3wEuBdwJvBR4DbACeHBFPTyndHxEP\nB66lKAZ/WT736cB/K5/jO8Argb8GPlTeAL5U/nle+bzvBG4D/gvwCuAXgRVts0xv35XAV4DXAs8D\nLoqIO8rHfLxc/hLgTRHx2ZTS/o48LqJ4GeeNwCOAjcB1EfHklNIPu2Qo6UhSSt68eevDG/CnwP3A\nso7lB4F3tn38Moofjn/fsd4N5eN3tC07DpgAPtG27Bnl41d1PP68cvmLy49/u3y+pxxh5oeVj7lk\nlvtOnGXZqvI5n962bEv5HH81y9z/Afxp2/KTgXs78nhW+fgJYEnb8t8tl6+v+2vrzdug3nx5Qloc\nEsVv8O1uLP98109WSukQ8DngjLb1fpdir8HHI+Jh0zfg88D3gWeX691FccxCKyLmvJcytf12HxEn\nlp/jxvI5h2bZnt2zzB0d23M3cFPH9kx7d0ppqm3dqyj2xJw/19klFSwN0uIx0fHx3eWf35hl+UPa\nPn4scArFyw7fabt9G3gwxa59UkqfBK6iePljsjyu4A8j4oSc4SLiIRHx1oi4DfhB+Tm+TlEQTs7c\nnvtSSnccZXumfbXLskfnzCtpJo9pkBaP++ewvP1dDscBt1McHzDbux++M/2XlNKLIuIc4PnAcyn2\nbvxJRDyt/bf6Lj5AcazFduCLFHsxjqM4TmK2X2Bmm7vbNua+a8N3d0jHwNIg9a+qTuD0NeBc4NMp\n4wDBlNJngc8CF0fEauB9FAdsvpMuM5fvwngOcHFK6c/blp957ON39dhZlv1nisIiaR58eULqX/eW\nf55yxLWO3fspfoG4pPOOiHhARJxc/n22OaZ/AJ9Y/jm9t6Fz3ek9BJ3fczbSu3L00oj42ekPIuL3\ngJ8Hru7R55MWPfc0SP1rlGJ3+l9ExB7gx8DHuqw7793uKaVPRcTbgddFxJOBfeXnehzFQZL/g+Lt\nky+LiFcDH6bYO/FzFG/rvJvyB3FK6b6I+AqwKiL+DbgT+NeU0pcj4lPA5vIYiFuAlRRvwezVSwZ3\nAPsj4l3AUoq3rv4b8I4efT5p0bM0SH0qpfS5iHg9xbkPnkvxW/pjKH4z7/ztfK6/rR+2fkrpVRHx\nOYpzIPw5xVsbbwbeQ/HWTYBPAr9C8TbJ0yjKwo3AS1JK/972dH9Ecc6Iy4ATgG3AlymOmXgb8GqK\nonAt8BvArXOYv9t6s+XxF8ATgddRFJzrgHUppfsyP5ekDpFSX173RpLmJSKeBfwD8LsppQ8dbX1J\n+eZ8TENE/FpEfDQibilP1dpqu+/4iBiOiC+Vp229JSLeHRE/3/EcD4mI95Wngb0zIt4REQ9eiA2S\nJEm9MZ8DIR8MfAFYx8xdgkuAJ1PsjnwK8EKKK/J9pGO9K4CzKI7Yfh7wTODt85hFkiRVZD5ndbsG\nuAaKi9x03HcPxWuvPxER64EbI+IXUkrfjIizynWWp5Q+X66zAfj7iPizlNJt89sUSfoJX3eVeqCK\nAyFPofgPfFf58dOAO6cLQ+n6cp2nMnOvhCRlK89c+YC655AWo56Whog4keIKc1eklL5fLl5KcXra\nn0jFFfTuKO+b7XkeRrF34mbAI58lScr3IIor0l6bUvrusTxRz0pDeUGbD1DsQXh1zkPovkvxuRRn\nnZMkSfPz+xTHFM5bT0pDW2F4FPCctr0MALdRXgCnbf0HUFxw5vYuT3kzwHvf+17OOuusBZ9Xs9u4\ncSOXXXZZ3WM0iplXz8yrZ+bVOnDgABdccAGUP0uPxYKXhrbCcAbw7JTSnR2rfAY4JSKe0nZcw7kU\nexpuZHb3AZx11lkMDXVeQVe9cvLJJ5t3xcy8emZePTOvzTG/vD/n0lCeT+FMfnrq1zMi4kkUp2y9\nFfggxdsufwt4YEScVq53R0rpxyml8Yi4FvjbiHgVxRnjdgAjvnOiv9x2m1+Oqpl59cy8emY+uOaz\np+FsirOtTZ/K9s3l8ndTnJ/h+eXyL5TLp49VeDbwqXLZS4CdFO+aOARcRXFeePWRW265pe4RGsfM\nq2fm1TPzwTWf8zR8kiOfFOqoJ4xKKd0FXDDXz61qLV++vO4RGsfMq2fm1TPzweWlsdXV6tWr6x6h\nccy8emZePTMfXANxwaqIGAJGR0dHPXhGkqQ5GBsbm967szylNHYsz+WeBkmSlMXSoK7WrFlT9wiN\nY+bVM/PqmfngsjSoq5UrV9Y9QuOYefXMvHpmPrg8pkGSpEXMYxokSVLlLA2SJCmLpUFd7d+/v+4R\nGsfMq2fm1TPzwWVpUFfbt2+ve4TGMfPqmXn1zHxwWRrU1Z49e+oeoXHMvHpmXj0zH1wLfmnsXvra\n177GiSeeWPcYc3Lqqady2mmnHX3FPrRkyZK6R2gcM6+emVfPzAfXQJWGF73oRXWPMGcnn/wwvv71\nf+OhD31o3aNIknRMBqo0wLuAx9c9xBz8X+6++zXcc889lgZJ0sAbsNLwRGCQTu50b90DHJNNmzbx\npje9qe4xGsXMq2fm1TPzweWBkOpq2bJldY/QOGZePTOvnpkProE6jTSMMlh7Gq4HzuPgwYOcfvrp\ndQ8jSWogTyMtSZIqZ2mQJElZBuxASFVpfHycJzzhCXWP0ShmXj0zr94nPvEJTjnllLrHmLNTTz21\n8cdjWBrU1ebNm/noRz9a9xiNYubVM/NqTUxMcN55Kzl06P66R5mzBz1oCTfddKDRxcHSoK527txZ\n9wiNY+bVM/NqTU5OloXhvcBZdY8zBwe4774LmJyctDRIs2nyf4y6mHn1zLwuZzFY74YTeCCkJEnK\nZGmQJElZLA3qanh4uO4RGsfMq2fmUj5Lg7qampqqe4TGMfPqmbmUz9KgrrZt21b3CI1j5tUzcymf\npUGSJGWxNEiSpCyWBnU1OTlZ9wiNY+bVM3Mpn6VBXa1du7buERrHzKtn5lI+S4O62rp1a90jNI6Z\nV8/MpXyWBnU1NOQpXqtm5tUzcymfpUGSJGWxNEiSpCyWBnW1e/fuukdoHDOvnplL+SwN6mpsbKzu\nERrHzKtn5lI+S4O62rVrV90jNI6ZV8/MpXyWBkmSlMXSIEmSssy5NETEr0XERyPilog4FBGtWdZ5\nQ0TcGhFTEXFdRJzZcf9DIuJ9EXF3RNwZEe+IiAcfy4ZIkqTems+ehgcDXwDWAanzzoh4LbAeeAVw\nDnAvcG1EnNC22hXAWcC5wPOAZwJvn8cs6qFWa0YfVI+ZefXMXMp3/FwfkFK6BrgGICJillVeA1ya\nUvpYuc5LgduBFwDvj4izgOcCy1NKny/X2QD8fUT8WUrptnltiRbc+vXr6x6hccy8emYu5VvQYxoi\n4jHAUuDj08tSSvcANwIrykVPA+6cLgyl6yn2Wjx1IefRsVm5cmXdIzSOmVfPzKV8C30g5FKKH/63\ndyy/vbxvep1vt9+ZUrofuKNtHUmS1GeqevdEMMvxD3Nf53yg1XFbAeztWG9feV+ndUDn2d/GynUn\nO5ZvAYY7lk2U6453LN8BbOpYNgVcPGOCkZER1qxZM2P5qlWr2Lv38O3Yt2/frK+3rlu3bsZZ7MbG\nxmi1WkxOHr4dW7ZsYXj48O2YmJig1WoxPn74duzYsYNNmw7fjqmpKVqtFvv373c73A63w+1YkO0o\nbKQ333dbwP6O5SPAzO2AVeT//HjjjCX9+PUYGRmh1WqxYsUKli5dSqvVYuPGjbNszzyllOZ9Aw4B\nrbaPH1Mue2LHev8IXFb+fQ3w3Y77HwD8GPjtLp9nCEgwmiAN0O26BKSDBw+mQfThD3+47hEax8yr\nZ+bVGh0dTYP5/byYe3R0tO4I5+ynmTOUjuFnfkppYfc0pJQOArdRvCsCgIg4ieJYhU+Xiz4DnBIR\nT2l76LkUexpuXMh5dGxGRkbqHqFxzLx6Zi7lm/O7J8rzKZxJ8UMe4IyIeBJwR0rpG8DlwOsj4qvA\nzcClwDeBjwCklMYj4lrgbyPiVcAJFPuZRpLvnOgrV155Zd0jNI6ZV8/MpXxzLg3A2cA/UOzqSMCb\ny+XvBtamlLZHxBKK8y6cAvwT8JsppR+1PcdLgJ0U75o4BFxF8VZNSZLUp+ZznoZPcpQDKFNKW4Gt\nR7j/LuCCuX5uSZJUH689IUmSslga1NVsb+1Rb5l59cxcymdpUFeeKa96Zl49M5fyWRrU1erVq+se\noXHMvHpmLuWzNEiSpCyWBkmSlMXSoK46z3uu3jPz6pm5lM/SoK62b99e9wiNY+bVM3Mpn6VBXe3Z\ns6fuERrHzKtn5lI+S4O6WrJkSd0jNI6ZV8/MpXyWBkmSlMXSIEmSslga1NWmTZvqHqFxzLx6Zi7l\nszSoq2XLltU9QuOYefXMXMpnaVBXGzZsqHuExjHz6pm5lM/SIEmSslgaJElSFkuDuhofH697hMYx\n8+qZuZTP0qCuNm/eXPcIjWPm1TNzKZ+lQV3t3Lmz7hEax8yrZ+ZSPkuDuvKtaNUz8+qZuZTP0iBJ\nkrJYGiRJUhZLg7oaHh6ue4TGMfPqmbmUz9KgrqampuoeoXHMvHpmLuWzNKirbdu21T1C45h59cxc\nymdpkCRJWSwNkiQpi6VBXU1OTtY9QuOYefXMXMpnaVBXa9eurXuExjHz6pm5lM/SoK62bt1a9wiN\nY+bVM3Mpn6VBXQ0NDdU9QuOYefXMXMpnaZAkSVksDZIkKYulQV3t3r277hEax8yrZ+ZSPkuDuhob\nG6t7hMYx8+qZuZTP0qCudu3aVfcIjWPm1TNzKZ+lQZIkZbE0SJKkLJYGSZKUZcFLQ0QcFxGXRsTX\nI2IqIr4aEa+fZb03RMSt5TrXRcSZCz2Ljk2r1ap7hMYx8+qZuZSvF3saXge8Ang18ARgM7A5ItZP\nrxARrwXWl+udA9wLXBsRJ/RgHs3T+vXrj76SFpSZV8/MpXzH9+A5VwAfSSldU348EREvoSgH014D\nXJpS+hhARLwUuB14AfD+HsykeVi5cmXdIzSOmVfPzKV8vdjT8Gng3Ih4LEBEPAl4OnB1+fFjgKXA\nx6cfkFK6B7iRonBIkqQ+1Is9DW8ETgLGI+J+imJyUUppT3n/UiBR7Flod3t5nyRJ6kO92NOwCngJ\n8GLgKcDLgE0R8QdHeVxQlAn1ib1799Y9QuOYefXMXMrXi9KwHfjLlNIHUkpfTim9D7gMuLC8/zaK\ngnBax+Mewcy9Dx3OB1odtxVA53/6feV9ndYBneeZHyvXnexYvgUY7lg2Ua473rF8B7CpY9kUcPGM\nCUZGRlizZs2M5atWrZrxzWvfvn2zHtm9bt26GefLHxsbo9VqMTl5+HZs2bKF4eHDt2NiYoJWq8X4\n+OHbsWPHDjZt+ul2jIyMMDU1RavVYv/+/QO7HcDAbMfIyMii2I52/b4dl1xyyaLYjkH6ehQ20pvv\nuy1gf8fyEWDmdhS/4+b+/HjjjCX9+PUYGRmh1WqxYsUKli5dSqvVYuPGjbNsz/xESgv7y31ETFK8\nHPH2tmUXAi9LKT2h/PhW4E0ppcvKj0+iKAwvTSl9YJbnHAJGYRQYWtB5e+t64DwOHjzI6aefXvcw\nklS7sbExli9fzuB9Px8DljM6OsrQ0CDN3Z45y1NKx3SxlV4c0/Ax4KKI+AbwZYp/FRuBd7Stcznw\n+oj4KnAzcCnwTeAjPZhHkiQtgF6UhvUUJWAXxUsOtwL/u1wGQEppe0QsAd4OnAL8E/CbKaUf9WAe\nSZK0ABa8NKSU7gX+pLwdab2twNaF/vySJKk3vPaEuprtgBv1lplXz8ylfJYGdeWZ8qpn5tUzcymf\npUFdrV69uu4RGsfMq2fmUj5LgyRJymJpkCRJWSwN6qrzbGTqPTOvnplL+SwN6mr79u11j9A4Zl49\nM5fyWRrU1Z49e46+khaUmVfPzKV8lgZ1tWTJkrpHaBwzr56ZS/ksDZIkKYulQZIkZbE0qKvOa7yr\n98y8emYu5bM0qKtly5bVPULjmHn1zFzKZ2lQVxs2bKh7hMYx8+qZuZTP0iBJkrJYGiRJUhZLg7oa\nHx+ve4TGMfPqmbmUz9KgrjZv3lz3CI1j5tUzcymfpUFd7dy5s+4RGsfMq2fmUj5Lg7ryrWjVM/Pq\nmbmUz9IgSZKyWBokSVIWS4O6Gh4ernuExjHz6pm5lM/SoK6mpqbqHqFxzLx6Zi7lszSoq23bttU9\nQuOYefXMXMpnaZAkSVksDZIkKYulQV1NTk7WPULjmHn1zFzKZ2lQV2vXrq17hMYx8+qZuZTP0qCu\ntm7dWvcIjWPm1TNzKZ+lQV0NDQ3VPULjmHn1zFzKZ2mQJElZLA2SJCmLpUFd7d69u+4RGsfMq2fm\nUj5Lg7oaGxure4TGMfPqmbmUz9Kgrnbt2lX3CI1j5tUzcymfpUGSJGWxNEiSpCyWBkmSlMXSoK5a\nrVbdIzSOmVfPzKV8lgZ1tX79+rpHaBwzr56ZS/l6Uhoi4pER8X8iYjIipiLiixEx1LHOGyLi1vL+\n6yLizF7MovlbuXJl3SM0jplXz8ylfAteGiLiFOAG4IfAc4GzgD8F7mxb57XAeuAVwDnAvcC1EXHC\nQs8jSZIWxvE9eM7XARMppT9uW/bvHeu8Brg0pfQxgIh4KXA78ALg/T2YSZIkHaNevDzxfOBzEfH+\niLg9IsYi4icFIiIeAywFPj69LKV0D3AjsKIH82ie9u7dW/cIjWPm1TNzKV8vSsMZwKuAm4CVwF8D\nb4uIC8r7lwKJYs9Cu9vL+9QnRkZG6h6hccy8emYu5etFaTgOGE0pXZxS+mJK6W+Av6UoEkcSFGXi\nCM4HWh23FUDnbwr7yvs6rQM6L04zVq472bF8CzDcsWyiXHe8Y/kOYFPHsing4hkTjIyMsGbNmhnL\nV61aNeM3nn379s36drB169bNuMjO2NgYrVaLycnDt2PLli0MDx++HRMTE7RaLcbHD9+OHTt2sGnT\nT7fjyiuvZGpqilarxf79+wd2O4CB2Y4rr7xyUWxHu37fjqGhw47RHtjtGKSvR2Ejvfm+2wL2dywf\nAWZuB6wi/+fHG2cs6cevx8jICK1WixUrVrB06VJarRYbN26cZXvmJ1I6ys/puT5hxM3AvpTSf29b\n9krgopTSo8qXJ74GPDml9KW2df4R+HxKacbWle+8GIVRYKjz7j52PXAeBw8e5PTTT697GEmq3djY\nGMuXL2fwvp+PAcsZHR2dUTT73U8zZ3lK6Ziu0NaLPQ03AI/vWPZ4yoMhU0oHgduAc6fvjIiTgKcC\nn+7BPJIkaQH04t0TlwE3RMSFFO+EeCrwx8DL29a5HHh9RHwVuBm4FPgm8JEezCNJkhbAgu9pSCl9\nDnghsBr4F+Ai4DUppT1t62yneEHq7RTvmvgZ4DdTSj9a6Hk0f7O9dqbeMvPqmbmUrxd7GkgpXQ1c\nfZR1tgJbe/H5tTA8U171zLx6Zi7l89oT6mr16tV1j9A4Zl49M5fyWRokSVIWS4MkScpiaVBXnScW\nUe+ZefXMXMpnaVBX27dvr3uExjHz6pm5lM/SoK727Nlz9JW0oMy8emYu5bM0qKslS5bUPULjmHn1\nzFzKZ2mQJElZLA2SJCmLpUFddV6uVb1n5tUzcymfpUFdLVu2rO4RGsfMq2fmUj5Lg7rasGFD3SM0\njplXz8ylfJYGSZKUxdIgSZKyWBrU1fj4eN0jNI6ZV8/MpXyWBnW1efPmukdoHDOvnplL+SwN6mrn\nzp11j9A4Zl49M5fyWRrUlW9Fq56ZV8/MpXyWBkmSlMXSIEmSslga1NXw8HDdIzSOmVfPzKV8lgZ1\nNTU1VfcIjWPm1TNzKZ+lQV1t27at7hEax8yrZ+ZSPkuDJEnKYmmQJElZLA3qanJysu4RGsfMq2fm\nUj5Lg7pau3Zt3SM0jplXz8ylfJYGdbV169a6R2gcM6+emUv5LA3qamhoqO4RGsfMq2fmUj5LgyRJ\nymJpkCRJWSwN6mr37t11j9A4Zl49M5fyWRrU1djYWN0jNI6ZV8/MpXyWBnW1a9euukdoHDOvnplL\n+SwNkiQpi6VBkiRlsTRIkqQslgZ11Wq16h6hccy8emYu5bM0qKv169fXPULjmHn1zFzKZ2lQVytX\nrqx7hMYx8+qZuZTP0iBJkrL0vDRExIURcSgi3tK27MSI2BURkxHxvYi4KiIe0etZJEnS/PW0NETE\nrwAvB77YcdflwPOA3wGeCTwS+GAvZ9Hc7d27t+4RGsfMq2fmUr6elYaI+FngvcAfA3e1LT8JWAts\nTCl9MqX0eWAN8PSIOKdX82juRkZG6h6hccy8emYu5evlnoZdwMdSSp/oWH42cDzw8ekFKaWbgAlg\nRQ/n0RxdeeWVdY/QOGZePTOX8h3fiyeNiBcDT6YoCJ1OA36UUrqnY/ntwNJezCNJko7dgu9piIhf\noDhm4YKU0o/n8lAgHXmV84FWx20F0Pma5L7yvk7rgM7L4I6V6052LN8CDHcsmyjXHe9YvgPY1LFs\nCrh4xgQjIyOsWbNmxvJVq1bNeG113759s554Zt26dTMu5zs2Nkar1WJy8vDt2LJlC8PDh2/HxMQE\nrVaL8fHDt2PHjh1s2nT4dkxNTdFqtdi/f7/b4Xa4HW7HgmxHYSO9+b7bAvZ3LB+heBW80yryf368\nccaSfvx6jIyM0Gq1WLFiBUuXLqXVarFx48ZZtmd+IqWj/Jye6xNG/DbwIeB+iiIA8ACKQnA/8BvA\n9cAp7XsbIuJm4LKU0ltnec4hYBRGgaEFnbe3rgfO4+DBg5x++ul1DyNJtRsbG2P58uUM3vfzMWA5\no6OjDA0N0tztmbM8pXRM14LvxTEN1wO/TPHyxJPK2+coDoqc/vuPgXOnHxARjwOWAZ/pwTyap9ka\nrXrLzKtn5lK+BT+mIaV0L/CV9mURcS/w3ZTSgfLj3cBbIuJO4HvA24AbUkqfXeh5NH+eKa96Zl49\nM5fy9eRAyFl0vgaykeKliquAE4FrKA44UB9ZvXp13SM0jplXz8w1FwcOHKh7hDlbyJkrKQ0pped0\nfPxDYEN5kySpz30LOI4LLrig7kFqVdWeBkmSBthdwCGKw/POqnmWubqa2d7NNx+WBnW1f/9+nvGM\nZ9Q9RqOYefXMXHNzFoP1rg+AhXt5wqtcqqvt27fXPULjmHn1zFzKZ2lQV3v27Kl7hMYx8+qZuZTP\n0qCulixZUvcIjWPm1TNzKZ+lQZIkZbE0SJKkLJYGddV5ERX1nplXz8ylfJYGdbVs2bK6R2gcM6+e\nmUv5LA3qasMGT9hZNTOvnplL+SwNkiQpi6VBkiRlsTSoq/Hx8bpHaBwzr56ZS/ksDepq8+bNdY/Q\nOGZePTOX8nnBKnV14YUXMjY2VvcYc3bqqacO7BHxO3furHuExjFzKZ+lQbOamJjgOc/5de67b6ru\nUebsQQ9awk03HRjI4jCIMw86M5fyWRo0q8nJybIwDNq14w9w330XMDk56Q8DSVpglgYdxSBeO16S\n1AseCCn1keHh4bpHaBwzl/JZGqQ+MjU1eMeQDDozl/JZGqQ+sm3btrpHaBwzl/JZGiRJUhZLgyRJ\nymJpkPrI5ORk3SM0jplL+SwNUh9Zu3Zt3SM0jplL+SwNUh/ZunVr3SM0jplL+SwNUh8ZGvJEWlUz\ncymfpUGSJGWxNEiSpCyWBqmP7N69u+4RGsfMpXyWBqmPjI2N1T1C45i5lM/SIPWRXbt21T1C45i5\nlM/SIEmSslgaJElSFkuDJEnKYmmQ+kir1ap7hMYxcymfpUHqI+vXr697hMYxcymfpUHqIytXrqx7\nhMYxcymfpUGSJGWxNEiSpCwLXhoi4sKI+GxE3BMRt0fEhyPicR3rnBgRuyJiMiK+FxFXRcQjFnoW\nadDs3bu37hEax8ylfL3Y0/BrwA7gqcCvAw8E9kXEz7StcznwPOB3gGcCjwQ+2INZpIEyMjJS9wiN\nY+ZSvuMX+glTSue3fxwRfwh8G1gO7I+Ik4C1wItTSp8s11kDHIiIc1JKn13omaRBceWVV9Y9QuOY\nuZSvimMaTgEScEf58XKKsvLx6RVSSjcBE8CKCuaRJEnz0NPSEBFB8VLE/pTSV8rFS4EfpZTu6Vj9\n9vI+SZLUhxb85YkOfwX8IvCMjHWDYo+EJEnqQz3b0xARO4Hzgf+aUrq17a7bgBPKYxvaPYJib8MR\nnA+0Om4rgM6jn/eV93VaB+zuWDZWrjvZsXwLMNyxbKJcd7xj+Q5gU8eyKeDiGROMjIywZs2aGctX\nrVo14yjuffv2zXqK23Xr1rF79+HbMTY2RqvVYnLy8O3YsmULw8OHb8fExAStVovx8cO3Y8eOHWza\n1LkdP6Ckr46gAAAI1UlEQVTY5v2dWwLM3A5YRf1fD7j88ssP+3hqaopWq8X+/YdvR799Pdpnme3r\nMSjb0a7ft+Pss89eFNsxSF+PwkZ68323V9+v/m6WZb38+THf7Rjhpz8bl5Z/f/Msj5mnlNKC34Cd\nwDeAM2a57yTgh8AL25Y9DjgEnNPl+YaABKMJ0gDdrktAOnjwYBo0o6OjaTAzL+YeHR2tO8J5ueKK\nK+oeoXHMvFqD+73lvQM6d/vsDKV0bD/fF/zliYj4K2A1Rb25NyJOK++6O6V0X0rpnojYDbwlIu4E\nvge8Dbgh+c4JNdzq1avrHqFxzFzK14tjGl5J0Wj+sWP5GuA95d83AvcDVwEnAtdQ7KuWJEl9qhfn\naTjqcRIppR8CG8qbJEkaAF57QuojnQeiqffMXMpnaZD6yPbt2+seoXHMXMpnaZD6yJ49e+oeoXHM\nXMpnaZD6yJIlS+oeoXHMXMpnaZAkSVksDZIkKYulQeojM0/jrV4zcymfpUHqI8uWLat7hMYxcymf\npUHqIxs2eL6zqpm5lM/SIEmSslgaJElSFkuD1EfGx8frHqFxzFzKZ2mQ+sjmzZvrHqFxzFzKZ2mQ\n+sjOnTvrHqFxzFzKZ2mQ+ohv/6uemUv5LA2SJCmLpUGSJGWxNEh9ZHh4uO4RGsfMpXyWBqmPTE1N\n1T1C45i5lM/SIPWRbdu21T1C45i5lM/SIEmSslgaJElSFkuD1EcmJyfrHqFxzFzKZ2mQ+sjatWvr\nHqFxzFzKZ2mQ+sjWrVvrHqFxzFzKZ2mQ+sjQ0FDdIzSOmUv5LA2SJCmLpUGSJGWxNEh9ZPfu3XWP\n0DhmLuWzNEh9ZGxsrO4RGsfMpXyWBqmP7Nq1q+4RGsfMpXyWBkmSlMXSIEmSslgaJElSFkuD1Eda\nrVbdIzSOmUv5LA1SH1m/fn3dIzSOmUv5LA1SH1m5cmXdIzSOmUv5LA2SJCmLpUGSJGWxNEh9ZO/e\nvXWP0DhmLuWzNEh9ZHh4uO4RGsfMpXy1loaIWBcRByPiBxHxzxHxK3XOI9Xt4Q9/eN0jNI6ZS/lq\nKw0RsQp4M7AFeArwReDaiDi1rpkkSVJ3de5p2Ai8PaX0npTSOPBKYApYW+NMkiSpi1pKQ0Q8EFgO\nfHx6WUopAdcDK+qYSZIkHdnxNX3eU4EHALd3LL8dePws6z+o+ONDwOd6OdcCOwAUR2cP2uumBw8e\nLP92NdPbMRiKua+++moOHBikuQs33HAD73vf++oeY86OO+44Dh06VPcY82Lm1Rrc7y03lH8O2tzw\n09mnf5bOXxS/4FcrIn4euAVYkVK6sW35duAZKaVf7Vj/JcDg/a+WJKl//H5K6YpjeYK69jRMAvcD\np3UsfwQz9z4AXAv8PnAzcF9PJ5MkaXF5EHA6xc/SY1LLngaAiPhn4MaU0mvKjwOYAN6WUnpTLUNJ\nkqSu6trTAPAW4N0RMQp8luLdFEuAv6txJkmS1EVtpSGl9P7ynAxvoHiZ4gvAc1NK36lrJkmS1F1t\nL09IkqTB4rUnJElSFkuDJEnK0relISKOi4hLI+LrETEVEV+NiNfXPddiFxE/GxGXR8TNZe77I+Ls\nuudaTCLi1yLioxFxS0QciojWLOu8ISJuLb8G10XEmXXMulgcLfOIeGFEXBMR3ynvf2Jdsy4WR8o8\nIo6PiOGI+FJEfL9c593lOXw0Txn/zrdExIEy8zvK7y3nzOVz9G1pAF4HvAJ4NfAEYDOwOSLW1zrV\n4rcbOJfivBi/BFwHXO9/5gX1YIoDf9cBMw4qiojXAusp/v2fA9xLcTG3E6occpE5Yubl/fuB13a5\nX3N3pMyXAE8GtlFcsPCFFGcD/kiVAy5CR/t3flN53y8BT6c499G+iHhY7ifo2wMhI+JjwG0ppZe3\nLbsKmEopvbS+yRaviHgQ8D3g+Smla9qWfw64OqV0SW3DLVIRcQh4QUrpo23LbgXelFK6rPz4JIqT\nnr0spfT+eiZdPGbLvO2+R1Oci/zJKaUvVT7cInWkzNvWORu4EXh0SumblQ23SGVm/nPA3cC5KaV/\nyHneft7T8Gng3Ih4LEBEPImiGV1d61SL2/EU1wT5YcfyHwDPqH6c5omIxwBLOfxibvdQfDP1Ym5a\nzE6h+O34rroHaYLywpGvoMj7i7mPq/PkTkfzRuAkYDwi7qcoOBellPbUO9bilVL6fkR8Brg4IsYp\nfrt9CcUPq/9X63DNsZTiG+dsF3NbWv04Uu9FxIkU3/OvSCl9v+55FrOIeB6wh+IloluB81JKd+Q+\nvp/3NKyi+IH1YorXvF4GbIqIP6h1qsXvAiAoLih2H8Vr61dQXCtE9Ql8rV2LUEQcD3yA4t/3q2se\npwk+ATyJ4pfBa4APlCdazNLPpWE78JcppQ+klL6cUnofcBlwYc1zLWoppYMppWdTHFDzqJTS04AT\nmL7mtHrtNoqCkHsxN2lgtRWGRwEr3cvQeymlH6SUvp5S+mx5zOB/AH+U+/h+Lg1LmPmb1SH6e+ZF\no/yHdXtEPAR4LrC37pmaIKV0kKI4nDu9rDwQ8qkUx/mo99yjU4G2wnAGxYF4d9Y8UlMdB5yYu3I/\nH9PwMeCiiPgG8GVgiOKiVu+odapFLiJWUvymexPwWIo9PgfwQmILJiIeDJxJkTPAGeWBvneklL4B\nXA68PiK+SvGWqEuBb+Lb0ebtaJmX5XgZ8J/KdZ5QXnn3tpSSe3jm4UiZU7yW/kGKt13+FvDAiJje\nu3ZHSunHVc+7GBwl8+8CFwEfBb4FnErx8vMjKcpbnpRSX94odo+/hWK3+L0UB+JtA46ve7bFfAN+\nD/gqxTsmbgHeCvxc3XMtphvwLIq9Zvd33N7Zts5Wim+sU8C1wJl1zz3It6NlTnHM1Gz3X1L37IN6\nO1LmwKNnuW/642fWPfug3o6S+YkURe0b5ff3bwIfBobm8jn69jwNkiSpv3h8gCRJymJpkCRJWSwN\nkiQpi6VBkiRlsTRIkqQslgZJkpTF0iBJkrJYGiRJUhZLgyRJymJpkCRJWSwNkiQpy/8HTpNuZ7ss\nxBsAAAAASUVORK5CYII=\n", 150 | "text/plain": [ 151 | "" 152 | ] 153 | }, 154 | "metadata": {}, 155 | "output_type": "display_data" 156 | } 157 | ], 158 | "source": [ 159 | "df_ts_diffs.hist()" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": null, 165 | "metadata": { 166 | "collapsed": true 167 | }, 168 | "outputs": [], 169 | "source": [] 170 | } 171 | ], 172 | "metadata": { 173 | "kernelspec": { 174 | "display_name": "Python 2", 175 | "language": "python", 176 | "name": "python2" 177 | }, 178 | "language_info": { 179 | "codemirror_mode": { 180 | "name": "ipython", 181 | "version": 2 182 | }, 183 | "file_extension": ".py", 184 | "mimetype": "text/x-python", 185 | "name": "python", 186 | "nbconvert_exporter": "python", 187 | "pygments_lexer": "ipython2", 188 | "version": "2.7.12" 189 | } 190 | }, 191 | "nbformat": 4, 192 | "nbformat_minor": 2 193 | } 194 | -------------------------------------------------------------------------------- /extras/recorder/test.out.sample: -------------------------------------------------------------------------------- 1 | timestamp ir_level red_level 2 | 7 40164 39722 3 | 19 40172 39728 4 | 27 40156 39724 5 | 39 40166 39724 6 | 47 40153 39729 7 | 60 40169 39723 8 | 68 40154 39727 9 | 80 40165 39711 10 | 88 40186 39725 11 | 101 40180 39737 12 | 109 40190 39716 13 | 121 40206 39731 14 | 129 40207 39726 15 | 142 40201 39721 16 | 150 40205 39721 17 | 162 40193 39680 18 | 170 40139 39675 19 | 183 40090 39656 20 | 191 40040 39606 21 | 203 39945 39581 22 | 211 39870 39543 23 | 223 39785 39512 24 | 232 39690 39475 25 | 244 39625 39422 26 | 252 39559 39406 27 | 264 39490 39362 28 | 273 39446 39349 29 | 285 39405 39316 30 | 297 39376 39326 31 | 305 39364 39313 32 | 317 39336 39287 33 | 326 39313 39274 34 | 338 39294 39278 35 | 346 39295 39265 36 | 358 39294 39273 37 | 367 39296 39249 38 | 379 39282 39258 39 | 387 39269 39268 40 | 399 39271 39262 41 | 408 39276 39245 42 | 420 39295 39256 43 | 428 39295 39253 44 | 440 39319 39270 45 | 449 39316 39265 46 | 461 39322 39270 47 | 469 39322 39270 48 | 481 39348 39282 49 | 490 39336 39268 50 | 502 39352 39269 51 | 510 39358 39257 52 | 522 39357 39263 53 | 531 39359 39260 54 | 543 39354 39259 55 | 551 39364 39258 56 | 563 39370 39275 57 | 572 39370 39258 58 | 584 39358 39267 59 | 592 39344 39248 60 | 604 39343 39246 61 | 613 39331 39255 62 | 625 39338 39245 63 | 633 39323 39258 64 | 645 39324 39260 65 | 654 39334 39243 66 | 666 39334 39229 67 | 674 39338 39247 68 | 686 39338 39238 69 | 695 39351 39231 70 | 707 39373 39231 71 | 715 39375 39255 72 | 727 39379 39249 73 | 735 39388 39246 74 | 748 39395 39246 75 | 756 39414 39251 76 | 768 39416 39264 77 | 776 39445 39264 78 | 789 39434 39283 79 | 797 39441 39253 80 | 809 39460 39252 81 | 817 39473 39269 82 | 830 39475 39269 83 | 838 39480 39270 84 | 850 39491 39261 85 | 858 39492 39277 86 | 871 39499 39277 87 | 879 39499 39284 88 | 891 39498 39271 89 | 899 39515 39257 90 | 912 39523 39292 91 | 920 39528 39286 92 | 932 39531 39282 93 | 940 39534 39284 94 | 953 39548 39290 95 | 961 39554 39276 96 | 973 39548 39293 97 | 981 39564 39291 98 | 994 39586 39285 99 | 1002 39584 39302 100 | 1014 39609 39295 101 | 1022 39608 39288 102 | 1034 39611 39291 103 | 1043 39589 39282 104 | 1055 39559 39252 105 | 1063 39525 39231 106 | 1075 39475 39194 107 | 1084 39400 39154 108 | 1096 39319 39128 109 | 1104 39238 39097 110 | 1117 39155 39043 111 | 1125 39074 39014 112 | 1137 39009 38966 113 | 1145 38959 38965 114 | 1157 38897 38950 115 | 1166 38860 38908 116 | 1178 38824 38905 117 | 1186 38787 38881 118 | 1198 38770 38884 119 | 1206 38760 38868 120 | 1219 38742 38858 121 | 1227 38725 38850 122 | 1239 38711 38834 123 | 1247 38708 38836 124 | 1260 38710 38825 125 | 1268 38698 38818 126 | 1280 38683 38824 127 | 1288 38680 38836 128 | 1301 38658 38844 129 | 1309 38674 38839 130 | 1321 38685 38836 131 | 1329 38703 38841 132 | 1342 38708 38837 133 | 1350 38730 38838 134 | 1362 38732 38844 135 | 1370 38749 38873 136 | 1383 38745 38855 137 | 1391 38734 38862 138 | 1403 38740 38839 139 | 1411 38754 38839 140 | 1424 38755 38844 141 | 1432 38743 38834 142 | 1444 38756 38822 143 | 1452 38751 38831 144 | 1465 38739 38828 145 | 1473 38740 38820 146 | 1485 38742 38814 147 | 1493 38737 38818 148 | 1505 38727 38826 149 | 1514 38734 38815 150 | 1526 38742 38812 151 | 1534 38730 38823 152 | 1546 38752 38821 153 | 1555 38759 38830 154 | 1567 38775 38806 155 | 1575 38777 38832 156 | 1588 38778 38828 157 | 1596 38796 38817 158 | 1608 38793 38818 159 | 1616 38812 38839 160 | 1628 38822 38843 161 | 1637 38853 38847 162 | 1649 38844 38841 163 | 1657 38866 38852 164 | 1669 38879 38861 165 | 1678 38885 38854 166 | 1690 38891 38867 167 | 1698 38910 38848 168 | 1710 38907 38880 169 | 1718 38929 38847 170 | 1731 38941 38870 171 | 1739 38953 38870 172 | 1751 38966 38875 173 | 1759 38976 38874 174 | 1772 38985 38883 175 | 1780 38996 38878 176 | 1792 38993 38886 177 | 1804 39009 38867 178 | 1813 39018 38888 179 | 1825 39021 38897 180 | 1833 39025 38897 181 | 1845 39044 38881 182 | 1854 39038 38884 183 | 1866 39054 38888 184 | 1874 39056 38884 185 | 1886 39070 38894 186 | 1895 39099 38914 187 | 1907 39088 38907 188 | 1915 39098 38913 189 | 1927 39095 38908 190 | 1936 39098 38910 191 | 1948 39114 38897 192 | 1956 39085 38906 193 | 1968 39072 38897 194 | 1977 39002 38867 195 | 1989 38952 38833 196 | 1997 38875 38795 197 | 2009 38801 38742 198 | 2017 38686 38716 199 | 2030 38597 38654 200 | 2038 38488 38623 201 | 2050 38394 38576 202 | 2058 38321 38535 203 | 2071 38240 38498 204 | 2079 38174 38485 205 | 2091 38114 38451 206 | 2099 38096 38427 207 | 2112 38047 38427 208 | 2120 38013 38418 209 | 2132 37994 38398 210 | 2140 37991 38391 211 | 2152 37976 38401 212 | 2161 37966 38390 213 | 2173 37944 38374 214 | 2181 37954 38369 215 | 2193 37931 38380 216 | 2202 37934 38356 217 | 2214 37927 38365 218 | 2222 37947 38373 219 | 2234 37974 38381 220 | 2243 37994 38381 221 | 2255 38001 38393 222 | 2263 38037 38399 223 | 2275 38072 38412 224 | 2284 38101 38424 225 | 2296 38115 38432 226 | 2304 38141 38432 227 | 2316 38142 38442 228 | 2325 38160 38450 229 | 2337 38183 38454 230 | 2345 38170 38453 231 | 2357 38176 38455 232 | 2366 38176 38451 233 | 2378 38185 38452 234 | 2386 38188 38440 235 | 2398 38185 38449 236 | 2407 38173 38439 237 | 2419 38172 38434 238 | 2427 38173 38439 239 | 2439 38193 38449 240 | 2448 38194 38442 241 | 2460 38201 38462 242 | 2468 38218 38453 243 | 2480 38222 38453 244 | 2488 38247 38469 245 | 2501 38261 38469 246 | 2509 38286 38476 247 | 2521 38276 38481 248 | 2529 38298 38480 249 | 2542 38321 38481 250 | 2550 38343 38489 251 | 2562 38354 38508 252 | 2570 38354 38525 253 | 2583 38372 38508 254 | 2591 38386 38503 255 | 2603 38387 38515 256 | 2611 38408 38522 257 | 2624 38418 38536 258 | 2632 38442 38547 259 | 2644 38461 38545 260 | 2652 38468 38534 261 | 2664 38478 38548 262 | 2673 38496 38559 263 | 2685 38516 38559 264 | 2693 38539 38572 265 | 2706 38538 38573 266 | 2714 38536 38572 267 | 2726 38555 38591 268 | 2734 38553 38578 269 | 2747 38589 38577 270 | 2755 38605 38581 271 | 2767 38604 38575 272 | 2775 38625 38590 273 | 2787 38625 38601 274 | 2796 38638 38606 275 | 2808 38657 38596 276 | 2816 38665 38599 277 | 2828 38656 38616 278 | 2837 38678 38614 279 | 2849 38720 38611 280 | 2857 38710 38634 281 | 2869 38734 38631 282 | 2878 38738 38638 283 | 2890 38732 38639 284 | 2898 38739 38616 285 | 2910 38729 38618 286 | 2919 38701 38592 287 | 2931 38650 38545 288 | 2939 38591 38530 289 | 2951 38536 38477 290 | 2960 38446 38447 291 | 2972 38377 38407 292 | 2980 38323 38379 293 | 2992 38250 38360 294 | 3000 38204 38333 295 | 3013 38166 38319 296 | 3021 38128 38306 297 | 3033 38102 38293 298 | 3041 38084 38290 299 | 3054 38067 38265 300 | 3062 38041 38246 301 | 3074 38014 38240 302 | 3082 38016 38243 303 | 3095 38010 38234 304 | 3103 37989 38215 305 | 3115 37982 38223 306 | 3123 37991 38219 307 | 3136 37989 38217 308 | 3144 37978 38233 309 | 3156 37988 38218 310 | 3164 37997 38226 311 | 3177 38022 38226 312 | 3185 38033 38235 313 | 3197 38035 38241 314 | 3205 38065 38263 315 | 3218 38073 38258 316 | 3226 38089 38270 317 | 3238 38095 38270 318 | 3246 38105 38281 319 | 3259 38123 38270 320 | 3267 38125 38279 321 | 3279 38138 38262 322 | 3287 38133 38268 323 | 3299 38133 38269 324 | 3308 38122 38267 325 | 3320 38127 38268 326 | 3328 38108 38253 327 | 3340 38109 38259 328 | 3352 38125 38237 329 | 3361 38125 38249 330 | 3373 38117 38249 331 | 3381 38147 38255 332 | 3393 38140 38256 333 | 3402 38169 38267 334 | 3414 38164 38252 335 | 3422 38173 38265 336 | 3434 38198 38258 337 | 3443 38193 38268 338 | 3455 38216 38257 339 | 3463 38237 38277 340 | 3475 38250 38292 341 | 3484 38258 38297 342 | 3496 38254 38306 343 | 3504 38284 38304 344 | 3516 38309 38307 345 | 3525 38303 38303 346 | 3537 38326 38319 347 | 3545 38329 38319 348 | 3557 38349 38324 349 | 3566 38380 38326 350 | 3578 38366 38330 351 | 3586 38372 38331 352 | 3598 38390 38349 353 | 3607 38405 38347 354 | 3619 38403 38357 355 | 3627 38426 38341 356 | 3639 38418 38344 357 | 3648 38451 38342 358 | 3660 38458 38354 359 | 3668 38466 38362 360 | 3680 38492 38359 361 | 3689 38491 38369 362 | 3701 38502 38361 363 | 3709 38513 38369 364 | 3721 38530 38363 365 | 3729 38545 38391 366 | 3742 38551 38389 367 | 3750 38555 38390 368 | 3762 38571 38381 369 | 3770 38586 38393 370 | 3782 38600 38392 371 | 3791 38610 38395 372 | 3803 38624 38388 373 | 3811 38643 38398 374 | 3823 38654 38412 375 | 3832 38646 38411 376 | 3844 38655 38417 377 | 3852 38684 38422 378 | 3865 38694 38415 379 | 3873 38688 38429 380 | 3885 38697 38404 381 | 3893 38684 38403 382 | 3905 38657 38373 383 | 3914 38616 38362 384 | 3926 38545 38327 385 | 3934 38482 38293 386 | 3947 38430 38259 387 | 3955 38355 38232 388 | 3967 38286 38207 389 | 3975 38235 38162 390 | 3987 38198 38135 391 | 3996 38151 38129 392 | 4008 38129 38114 393 | 4016 38114 38107 394 | 4028 38085 38111 395 | 4037 38081 38084 396 | 4049 38065 38088 397 | 4057 38054 38081 398 | 4069 38033 38073 399 | 4078 38031 38063 400 | 4090 38023 38068 401 | 4098 38027 38075 402 | 4110 38017 38047 403 | 4119 38009 38064 404 | 4131 38015 38063 405 | 4139 38021 38054 406 | 4151 38030 38067 407 | 4160 38037 38071 408 | 4172 38044 38068 409 | 4180 38089 38092 410 | 4192 38089 38080 411 | 4201 38099 38082 412 | 4213 38120 38091 413 | 4221 38143 38093 414 | 4233 38132 38102 415 | 4242 38137 38102 416 | 4254 38126 38078 417 | 4262 38133 38081 418 | 4274 38145 38100 419 | 4282 38136 38083 420 | 4295 38130 38085 421 | 4303 38125 38068 422 | 4315 38121 38079 423 | 4323 38123 38074 424 | 4336 38113 38067 425 | 4344 38142 38071 426 | 4356 38137 38075 427 | 4364 38135 38073 428 | 4377 38142 38061 429 | 4385 38162 38072 430 | 4397 38151 38071 431 | 4405 38175 38070 432 | 4418 38201 38070 433 | 4426 38210 38072 434 | 4438 38217 38086 435 | 4446 38227 38100 436 | 4458 38242 38090 437 | 4467 38266 38072 438 | 4479 38275 38093 439 | 4487 38272 38111 440 | 4500 38289 38105 441 | 4508 38298 38106 442 | 4520 38305 38114 443 | 4528 38322 38108 444 | 4541 38332 38123 445 | 4549 38341 38114 446 | 4561 38363 38130 447 | 4569 38367 38121 448 | 4581 38370 38131 449 | 4590 38380 38134 450 | 4602 38393 38137 451 | 4610 38395 38152 452 | 4622 38404 38147 453 | 4631 38403 38145 454 | 4643 38416 38133 455 | 4651 38417 38141 456 | 4663 38431 38144 457 | 4672 38428 38156 458 | 4684 38418 38150 459 | 4692 38434 38150 460 | 4704 38447 38156 461 | 4713 38450 38143 462 | 4725 38463 38157 463 | 4733 38463 38145 464 | 4745 38476 38177 465 | 4754 38497 38171 466 | 4766 38503 38166 467 | 4774 38513 38168 468 | 4786 38518 38167 469 | 4794 38524 38184 470 | 4807 38512 38165 471 | 4815 38481 38131 472 | 4827 38459 38117 473 | 4835 38415 38094 474 | 4848 38357 38065 475 | 4856 38304 38037 476 | 4868 38231 37999 477 | 4876 38160 37978 478 | 4889 38123 37949 479 | 4897 38058 37926 480 | 4909 38021 37916 481 | 4917 37980 37904 482 | 4929 37948 37881 483 | 4938 37934 37860 484 | 4950 37924 37863 485 | 4958 37908 37861 486 | 4971 37896 37842 487 | 4979 37897 37837 488 | 4991 37866 37843 489 | 4999 37862 37831 490 | 5012 37854 37833 491 | 5020 37829 37823 492 | 5032 37838 37823 493 | 5040 37837 37828 494 | 5052 37837 37808 495 | 5061 37850 37825 496 | 5073 37845 37819 497 | 5081 37856 37821 498 | 5093 37884 37825 499 | 5102 37886 37835 500 | 5114 37897 37831 501 | 5122 37903 37844 502 | 5134 37913 37848 503 | 5143 37932 37851 504 | 5155 37931 37854 505 | 5163 37913 37852 506 | 5175 37926 37841 507 | 5184 37913 37842 508 | 5196 37925 37846 509 | 5208 37903 37844 510 | 5216 37892 37813 511 | 5228 37896 37828 512 | 5237 37894 37826 513 | 5249 37906 37819 514 | 5257 37910 37819 515 | 5269 37924 37815 516 | 5278 37924 37815 517 | 5290 37941 37830 518 | 5298 37957 37834 519 | 5310 37982 37842 520 | 5319 37996 37840 521 | 5331 38011 37845 522 | 5339 38025 37855 523 | 5351 38029 37857 524 | 5360 38034 37865 525 | 5372 38059 37850 526 | 5380 38074 37861 527 | 5392 38083 37856 528 | 5401 38097 37857 529 | 5413 38107 37862 530 | 5421 38117 37852 531 | 5433 38138 37865 532 | 5442 38162 37884 533 | 5454 38164 37866 534 | 5462 38179 37880 535 | 5474 38196 37883 536 | 5483 38202 37896 537 | 5495 38213 37876 538 | 5503 38237 37901 539 | 5515 38242 37912 540 | 5524 38260 37909 541 | 5536 38264 37925 542 | 5544 38278 37931 543 | 5556 38302 37912 544 | 5564 38304 37922 545 | 5577 38322 37933 546 | 5585 38330 37944 547 | 5597 38349 37923 548 | 5605 38349 37943 549 | 5618 38362 37927 550 | 5626 38358 37935 551 | 5638 38372 37945 552 | 5646 38386 37946 553 | 5659 38399 37957 554 | 5667 38417 37949 555 | 5679 38433 37960 556 | 5687 38445 37967 557 | 5699 38438 37965 558 | 5708 38463 37979 559 | 5720 38462 37977 560 | 5728 38479 37979 561 | 5740 38477 37975 562 | 5749 38490 37974 563 | 5761 38513 37981 564 | 5769 38516 37978 565 | 5781 38541 37979 566 | 5790 38539 37971 567 | 5802 38552 37989 568 | 5810 38554 37993 569 | 5822 38562 37982 570 | 5831 38535 37961 571 | 5843 38502 37936 572 | 5851 38447 37894 573 | 5863 38387 37879 574 | 5872 38328 37839 575 | 5884 38275 37809 576 | 5892 38208 37778 577 | 5904 38151 37767 578 | 5913 38116 37738 579 | 5925 38068 37696 580 | 5933 38029 37694 581 | 5945 37997 37681 582 | 5954 37971 37682 583 | 5966 37951 37661 584 | 5974 37928 37642 585 | 5986 37915 37651 586 | 5995 37907 37641 587 | 6007 37896 37640 588 | 6015 37875 37619 589 | 6028 37877 37627 590 | 6035 37840 37614 591 | 6048 37830 37603 592 | 6056 37819 37606 593 | 6068 37825 37610 594 | 6076 37821 37609 595 | 6089 37832 37613 596 | 6097 37830 37605 597 | 6109 37833 37603 598 | 6117 37847 37620 599 | 6130 37851 37604 600 | 6138 37870 37611 601 | 6150 37886 37620 602 | 6158 37894 37622 603 | 6171 37889 37604 604 | 6179 37897 37623 605 | 6191 37899 37626 606 | 6199 37876 37622 607 | 6212 37880 37615 608 | 6220 37894 37615 609 | 6232 37890 37603 610 | 6240 37880 37605 611 | 6253 37880 37603 612 | 6261 37868 37612 613 | 6273 37848 37610 614 | 6281 37858 37605 615 | 6294 37871 37601 616 | 6302 37874 37605 617 | 6314 37875 37603 618 | 6322 37891 37608 619 | 6334 37873 37609 620 | 6343 37889 37612 621 | 6355 37902 37613 622 | 6363 37894 37618 623 | 6375 37911 37609 624 | 6384 37908 37604 625 | 6396 37916 37599 626 | 6404 37931 37626 627 | 6416 37933 37622 628 | 6425 37952 37621 629 | 6437 37959 37627 630 | 6445 37976 37627 631 | 6457 37962 37632 632 | 6466 37966 37651 633 | 6478 37975 37647 634 | 6486 37993 37643 635 | 6498 37993 37654 636 | 6507 38001 37641 637 | 6519 38016 37649 638 | 6527 38020 37641 639 | 6539 38020 37651 640 | 6547 38022 37651 641 | 6560 38032 37654 642 | 6568 38036 37648 643 | 6580 38051 37653 644 | 6588 38050 37665 645 | 6601 38063 37651 646 | 6609 38061 37656 647 | 6621 38065 37667 648 | 6629 38090 37671 649 | 6642 38086 37663 650 | 6650 38109 37680 651 | 6662 38105 37683 652 | 6670 38114 37677 653 | 6683 38110 37693 654 | 6691 38123 37683 655 | 6703 38122 37672 656 | 6711 38143 37678 657 | 6724 38136 37697 658 | 6732 38143 37687 659 | 6744 38151 37677 660 | 6752 38171 37698 661 | 6765 38164 37711 662 | 6777 38165 37707 663 | 6785 38190 37705 664 | 6797 38191 37702 665 | 6806 38203 37708 666 | 6817 38202 37702 667 | 6826 38200 37701 668 | 6838 38224 37710 669 | 6846 38214 37720 670 | 6858 38227 37711 671 | 6867 38223 37725 672 | 6879 38246 37713 673 | 6887 38242 37736 674 | 6899 38247 37722 675 | 6908 38260 37727 676 | 6920 38272 37739 677 | 6928 38266 37726 678 | 6940 38245 37709 679 | 6949 38221 37704 680 | 6961 38177 37667 681 | 6969 38111 37640 682 | 6981 38045 37618 683 | 6990 37960 37582 684 | 7002 37920 37538 685 | 7010 37851 37508 686 | 7022 37795 37480 687 | 7032 37751 37451 688 | 7043 37697 37445 689 | 7051 37674 37438 690 | 7063 37629 37406 691 | 7072 37625 37420 692 | 7084 37584 37396 693 | 7092 37570 37399 694 | 7104 37554 37386 695 | 7113 37541 37374 696 | 7125 37520 37362 697 | 7133 37519 37370 698 | 7145 37509 37343 699 | 7154 37494 37346 700 | 7166 37479 37348 701 | 7174 37487 37326 702 | 7186 37487 37316 703 | 7195 37478 37331 704 | 7207 37484 37334 705 | 7215 37487 37346 706 | 7227 37513 37349 707 | 7235 37535 37354 708 | 7248 37530 37357 709 | 7256 37551 37377 710 | 7268 37558 37371 711 | 7277 37566 37399 712 | 7289 37574 37353 713 | 7297 37563 37376 714 | 7309 37575 37372 715 | 7317 37582 37372 716 | 7330 37549 37356 717 | 7338 37559 37362 718 | 7350 37557 37358 719 | 7358 37553 37354 720 | 7371 37555 37363 721 | 7379 37554 37332 722 | 7391 37561 37343 723 | 7399 37553 37340 724 | 7412 37555 37338 725 | 7420 37536 37346 726 | 7432 37544 37345 727 | 7440 37559 37340 728 | 7453 37559 37350 729 | 7461 37560 37344 730 | 7473 37563 37352 731 | 7481 37563 37366 732 | 7493 37576 37365 733 | 7502 37591 37358 734 | 7514 37593 37365 735 | 7522 37611 37370 736 | 7534 37605 37367 737 | 7543 37627 37368 738 | 7555 37627 37364 739 | 7563 37655 37386 740 | 7575 37649 37385 741 | 7584 37668 37380 742 | 7596 37668 37397 743 | 7604 37687 37372 744 | 7616 37694 37397 745 | 7625 37717 37394 746 | 7637 37724 37408 747 | 7645 37715 37412 748 | 7657 37740 37422 749 | 7666 37738 37431 750 | 7678 37754 37430 751 | 7686 37769 37438 752 | 7698 37784 37439 753 | 7707 37793 37453 754 | 7719 37793 37452 755 | 7727 37810 37436 756 | 7739 37814 37440 757 | 7748 37831 37439 758 | 7760 37830 37442 759 | 7768 37842 37459 760 | 7780 37869 37462 761 | 7788 37858 37468 762 | 7801 37883 37464 763 | 7809 37873 37461 764 | 7821 37887 37466 765 | 7829 37900 37476 766 | 7842 37912 37480 767 | 7850 37909 37466 768 | 7862 37922 37482 769 | 7870 37932 37491 770 | 7883 37944 37481 771 | 7891 37960 37479 772 | 7903 37991 37488 773 | 7911 37983 37498 774 | 7924 37977 37504 775 | 7932 37994 37497 776 | 7944 38017 37512 777 | 7952 38017 37507 778 | 7965 38049 37530 779 | 7973 38032 37526 780 | 7985 38053 37520 781 | 7993 38059 37505 782 | 8006 38059 37518 783 | 8014 38057 37502 784 | 8026 38014 37513 785 | 8036 37961 37474 786 | 8046 37919 37439 787 | 8055 37837 37424 788 | 8067 37777 37381 789 | 8075 37685 37338 790 | 8087 37625 37307 791 | 8096 37535 37280 792 | 8108 37490 37268 793 | 8116 37437 37226 794 | 8128 37381 37206 795 | 8137 37375 37196 796 | 8149 37345 37192 797 | 8157 37322 37194 798 | 8169 37309 37159 799 | 8178 37279 37163 800 | 8190 37279 37164 801 | 8198 37258 37161 802 | 8210 37258 37156 803 | 8219 37258 37152 804 | 8231 37227 37134 805 | 8239 37226 37151 806 | 8251 37229 37143 807 | 8260 37232 37139 808 | 8272 37241 37150 809 | 8280 37248 37152 810 | 8292 37254 37157 811 | 8300 37264 37141 812 | 8313 37271 37165 813 | 8321 37282 37173 814 | 8333 37300 37170 815 | 8341 37301 37173 816 | 8354 37303 37178 817 | 8362 37322 37200 818 | 8374 37312 37183 819 | 8382 37307 37175 820 | 8395 37296 37184 821 | 8403 37302 37182 822 | 8415 37303 37163 823 | 8423 37289 37172 824 | 8436 37278 37173 825 | 8444 37275 37182 826 | 8456 37276 37175 827 | 8464 37259 37175 828 | 8477 37262 37166 829 | 8489 37274 37152 830 | 8497 37265 37172 831 | 8509 37263 37158 832 | 8518 37271 37149 833 | 8530 37264 37164 834 | 8538 37275 37148 835 | 8550 37273 37165 836 | 8559 37279 37170 837 | 8571 37284 37155 838 | 8579 37287 37161 839 | 8591 37299 37154 840 | 8600 37305 37179 841 | 8611 37300 37182 842 | 8620 37316 37188 843 | 8632 37325 37192 844 | 8640 37360 37192 845 | 8652 37369 37208 846 | 8661 37366 37198 847 | 8673 37390 37211 848 | 8681 37384 37210 849 | 8693 37387 37214 850 | 8702 37403 37230 851 | 8714 37418 37227 852 | 8722 37424 37220 853 | 8734 37428 37237 854 | 8743 37456 37231 855 | 8755 37470 37231 856 | 8763 37465 37237 857 | 8775 37478 37230 858 | 8784 37496 37249 859 | 8796 37489 37260 860 | 8804 37506 37264 861 | 8816 37518 37263 862 | 8825 37531 37271 863 | 8837 37536 37278 864 | 8845 37544 37291 865 | 8857 37551 37281 866 | 8866 37554 37267 867 | 8878 37552 37268 868 | 8886 37581 37274 869 | 8898 37576 37296 870 | 8907 37591 37290 871 | 8919 37581 37296 872 | 8927 37599 37299 873 | 8939 37611 37311 874 | 8948 37627 37298 875 | 8960 37650 37312 876 | 8968 37641 37322 877 | 8980 37655 37332 878 | 8989 37664 37330 879 | 9001 37675 37317 880 | 9009 37643 37303 881 | 9021 37613 37269 882 | 9030 37569 37242 883 | 9042 37505 37213 884 | 9050 37440 37170 885 | 9062 37344 37137 886 | 9070 37277 37117 887 | 9083 37207 37090 888 | 9091 37127 37056 889 | 9103 37086 37034 890 | 9111 37033 37013 891 | 9124 37002 37003 892 | 9132 36974 36983 893 | 9144 36953 36968 894 | 9152 36954 36972 895 | 9165 36924 36957 896 | 9173 36900 36962 897 | 9185 36903 36948 898 | 9193 36902 36956 899 | 9206 36885 36955 900 | 9214 36881 36939 901 | 9226 36877 36941 902 | 9234 36863 36942 903 | 9247 36840 36948 904 | 9255 36857 36948 905 | 9267 36857 36954 906 | 9275 36855 36945 907 | 9287 36879 36950 908 | 9296 36891 36968 909 | 9308 36919 36972 910 | 9316 36931 36973 911 | 9329 36940 36991 912 | 9337 36959 36996 913 | 9349 36967 36991 914 | 9357 36983 36995 915 | 9369 36995 37008 916 | 9378 36996 36998 917 | 9390 37015 36993 918 | 9398 37012 37011 919 | 9410 37020 37007 920 | 9419 37007 36991 921 | 9431 37006 37008 922 | 9439 37012 37008 923 | 9451 37003 37019 924 | 9460 37016 37002 925 | 9472 37039 37013 926 | 9480 37024 36994 927 | 9492 37033 36996 928 | 9500 37020 36996 929 | 9513 37044 37007 930 | 9521 37050 37024 931 | 9533 37052 37019 932 | 9542 37056 37020 933 | 9554 37073 37018 934 | 9562 37067 37020 935 | 9574 37084 37027 936 | 9582 37099 37027 937 | 9595 37102 37045 938 | 9603 37116 37030 939 | 9615 37119 37044 940 | 9623 37126 37034 941 | 9636 37150 37064 942 | 9644 37150 37071 943 | 9656 37166 37060 944 | 9664 37170 37068 945 | 9677 37180 37065 946 | 9685 37195 37069 947 | 9697 37203 37049 948 | 9705 37204 37094 949 | 9718 37226 37070 950 | 9726 37229 37090 951 | 9738 37251 37095 952 | 9746 37257 37102 953 | 9759 37272 37101 954 | 9767 37292 37108 955 | 9779 37293 37098 956 | 9787 37306 37126 957 | 9799 37317 37112 958 | 9808 37313 37120 959 | 9820 37333 37141 960 | 9828 37338 37141 961 | 9840 37349 37119 962 | 9849 37367 37133 963 | 9861 37382 37142 964 | 9869 37399 37156 965 | 9881 37401 37141 966 | 9890 37416 37159 967 | 9902 37407 37159 968 | 9910 37421 37173 969 | 9922 37412 37163 970 | 9931 37443 37161 971 | 9943 37440 37173 972 | 9955 37442 37178 973 | 9963 37468 37180 974 | 9975 37487 37177 975 | 9984 37495 37162 976 | 9996 37493 37194 977 | 10004 37496 37179 978 | 10016 37467 37163 979 | 10025 37445 37135 980 | 10037 37404 37112 981 | 10045 37333 37089 982 | 10057 37255 37051 983 | 10066 37162 37006 984 | 10078 37071 36973 985 | 10086 36976 36911 986 | 10098 36905 36864 987 | 10107 36842 36870 988 | 10119 36724 36822 989 | 10127 36679 36804 990 | 10139 36661 36785 991 | 10148 36643 36767 992 | 10160 36620 36776 993 | 10168 36588 36766 994 | 10180 36575 36766 995 | 10189 36554 36756 996 | 10201 36536 36751 997 | 10209 36541 36729 998 | 10221 36533 36730 999 | 10230 36520 36734 1000 | 10242 36509 36723 1001 | 10250 36505 36721 1002 | 10262 36511 36733 1003 | 10270 36509 36732 1004 | 10283 36525 36752 1005 | 10291 36527 36761 1006 | 10303 36559 36766 1007 | 10311 36581 36780 1008 | 10324 36608 36774 1009 | 10332 36618 36790 1010 | 10344 36639 36791 1011 | 10353 36655 36792 1012 | 10365 36657 36820 1013 | 10373 36648 36800 1014 | 10385 36654 36798 1015 | 10393 36657 36786 1016 | 10406 36655 36796 1017 | 10414 36654 36787 1018 | 10426 36659 36794 1019 | 10434 36646 36803 1020 | 10447 36643 36793 1021 | 10455 36636 36804 1022 | 10467 36636 36778 1023 | 10475 36629 36787 1024 | 10488 36619 36777 1025 | 10496 36648 36780 1026 | 10508 36639 36782 1027 | 10516 36638 36782 1028 | 10528 36644 36791 1029 | 10537 36649 36791 1030 | 10549 36661 36798 1031 | 10557 36668 36791 1032 | 10569 36673 36810 1033 | 10578 36690 36810 1034 | 10590 36706 36818 1035 | 10598 36695 36819 1036 | 10610 36729 36811 1037 | 10619 36728 36823 1038 | 10631 36736 36829 1039 | 10639 36761 36828 1040 | 10651 36762 36828 1041 | 10660 36771 36843 1042 | 10672 36796 36849 1043 | 10680 36807 36869 1044 | 10692 36807 36844 1045 | 10701 36821 36863 1046 | 10713 36835 36864 1047 | 10721 36832 36865 1048 | 10733 36859 36879 1049 | 10742 36860 36877 1050 | 10754 36872 36887 1051 | 10762 36891 36890 1052 | 10774 36925 36894 1053 | 10782 36918 36908 1054 | 10795 36938 36899 1055 | 10803 36949 36922 1056 | 10815 36967 36918 1057 | 10823 36977 36920 1058 | 10836 36988 36931 1059 | 10844 37013 36933 1060 | 10856 37012 36949 1061 | 10864 37021 36945 1062 | 10877 37042 36956 1063 | 10885 37053 36955 1064 | 10897 37080 36951 1065 | 10905 37068 36958 1066 | 10918 37092 36962 1067 | 10926 37109 36984 1068 | 10938 37123 36984 1069 | 10946 37164 36989 1070 | 10959 37163 36994 1071 | 10967 37175 37004 1072 | 10979 37179 37022 1073 | 10987 37194 37013 1074 | 11000 37200 37012 1075 | 11008 37175 37013 1076 | 11020 37161 36982 1077 | 11028 37123 36965 1078 | 11041 37060 36911 1079 | 11049 37007 36907 1080 | 11061 36900 36848 1081 | 11069 36844 36823 1082 | 11082 36752 36773 1083 | 11090 36663 36749 1084 | 11102 36609 36708 1085 | 11110 36534 36694 1086 | 11122 36495 36671 1087 | 11131 36463 36653 1088 | 11143 36446 36636 1089 | 11151 36416 36631 1090 | 11163 36394 36625 1091 | 11172 36386 36611 1092 | 11184 36387 36623 1093 | 11192 36371 36610 1094 | 11204 36364 36602 1095 | 11213 36366 36603 1096 | 11225 36326 36586 1097 | 11233 36318 36587 1098 | 11245 36331 36589 1099 | 11253 36337 36585 1100 | 11266 36355 36614 1101 | 11274 36357 36605 1102 | 11286 36375 36623 1103 | 11294 36398 36621 1104 | 11307 36415 36639 1105 | 11315 36431 36647 1106 | 11327 36458 36649 1107 | 11335 36476 36678 1108 | 11348 36497 36668 1109 | 11356 36495 36680 1110 | 11368 36520 36683 1111 | 11380 36495 36688 1112 | 11389 36501 36667 1113 | 11401 36506 36669 1114 | 11409 36493 36682 1115 | 11421 36504 36668 1116 | 11430 36489 36673 1117 | 11442 36501 36670 1118 | 11450 36495 36672 1119 | 11462 36500 36667 1120 | 11471 36487 36663 1121 | 11483 36488 36672 1122 | 11491 36495 36672 1123 | 11503 36515 36675 1124 | 11512 36524 36675 1125 | 11524 36529 36680 1126 | 11532 36531 36684 1127 | 11544 36541 36686 1128 | 11552 36555 36690 1129 | 11565 36565 36700 1130 | 11573 36585 36700 1131 | 11585 36602 36723 1132 | 11593 36621 36710 1133 | 11606 36636 36725 1134 | 11614 36646 36734 1135 | 11626 36640 36737 1136 | 11635 36666 36758 1137 | 11647 36688 36748 1138 | 11655 36688 36742 1139 | 11667 36708 36747 1140 | 11675 36702 36762 1141 | 11687 36728 36755 1142 | 11696 36740 36766 1143 | 11708 36754 36768 1144 | 11716 36768 36763 1145 | 11728 36757 36788 1146 | 11737 36773 36798 1147 | 11749 36774 36771 1148 | 11757 36787 36809 1149 | 11769 36797 36808 1150 | 11778 36817 36814 1151 | 11790 36815 36821 1152 | 11798 36818 36804 1153 | 11810 36829 36818 1154 | 11819 36848 36816 1155 | 11831 36862 36829 1156 | 11839 36870 36832 1157 | 11851 36865 36826 1158 | 11860 36872 36829 1159 | 11872 36898 36820 1160 | 11880 36903 36837 1161 | 11892 36919 36837 1162 | 11901 36919 36847 1163 | 11913 36927 36842 1164 | 11921 36936 36861 1165 | 11933 36939 36870 1166 | 11942 36955 36865 1167 | 11954 36982 36874 1168 | 11962 36947 36836 1169 | 11974 36934 36827 1170 | 11983 36889 36806 1171 | 11995 36819 36775 1172 | 12003 36748 36743 1173 | 12015 36670 36696 1174 | 12024 36584 36663 1175 | 12036 36504 36622 1176 | 12044 36427 36599 1177 | 12056 36367 36564 1178 | 12065 36324 36546 1179 | 12077 36294 36534 1180 | 12085 36278 36527 1181 | 12097 36227 36521 1182 | 12106 36234 36516 1183 | 12118 36193 36511 1184 | 12126 36195 36479 1185 | 12138 36176 36490 1186 | 12146 36163 36489 1187 | 12159 36174 36487 1188 | 12167 36173 36487 1189 | 12179 36161 36474 1190 | 12187 36167 36473 1191 | 12200 36151 36471 1192 | 12208 36146 36483 1193 | 12220 36168 36498 1194 | 12228 36167 36485 1195 | 12241 36185 36497 1196 | 12249 36215 36500 1197 | 12261 36249 36532 1198 | 12269 36266 36525 1199 | 12282 36303 36552 1200 | 12290 36307 36557 1201 | 12302 36342 36549 1202 | 12310 36342 36571 1203 | 12323 36344 36559 1204 | 12331 36354 36554 1205 | 12343 36358 36561 1206 | 12351 36353 36562 1207 | 12363 36344 36549 1208 | 12372 36347 36572 1209 | 12384 36351 36563 1210 | 12392 36348 36565 1211 | 12404 36347 36567 1212 | 12413 36351 36570 1213 | 12425 36351 36580 1214 | 12433 36354 36567 1215 | 12445 36370 36572 1216 | 12454 36384 36572 1217 | 12466 36389 36585 1218 | 12474 36389 36582 1219 | 12486 36406 36591 1220 | 12495 36425 36603 1221 | 12507 36438 36603 1222 | 12515 36454 36614 1223 | 12527 36476 36605 1224 | 12535 36484 36611 1225 | 12548 36500 36628 1226 | 12556 36499 36648 1227 | 12568 36531 36645 1228 | 12576 36545 36642 1229 | 12589 36554 36658 1230 | 12597 36569 36655 1231 | 12609 36578 36659 1232 | 12617 36594 36663 1233 | 12630 36613 36679 1234 | 12638 36622 36693 1235 | 12650 36633 36688 1236 | 12658 36651 36698 1237 | 12671 36667 36707 1238 | 12679 36690 36722 1239 | 12691 36703 36712 1240 | 12699 36736 36713 1241 | 12712 36733 36730 1242 | 12720 36756 36744 1243 | 12732 36781 36755 1244 | 12740 36800 36751 1245 | 12753 36803 36754 1246 | 12761 36807 36758 1247 | 12773 36842 36742 1248 | 12785 36859 36746 1249 | 12794 36840 36776 1250 | 12806 36869 36787 1251 | 12814 36885 36785 1252 | 12826 36891 36793 1253 | 12834 36910 36807 1254 | 12847 36913 36811 1255 | 12855 36935 36795 1256 | 12867 36948 36815 1257 | 12875 36958 36814 1258 | 12888 36966 36812 1259 | 12896 36971 36839 1260 | 12908 36998 36831 1261 | 12916 37011 36842 1262 | 12928 37037 36844 1263 | 12937 37022 36833 1264 | 12949 37052 36867 1265 | 12957 37061 36859 1266 | 12969 37069 36872 1267 | 12978 37092 36858 1268 | 12990 37096 36855 1269 | 12998 37092 36875 1270 | 13010 37061 36854 1271 | 13019 37025 36840 1272 | 13031 36972 36799 1273 | 13039 36882 36772 1274 | 13052 36805 36709 1275 | 13060 36740 36674 1276 | 13072 36564 36608 1277 | 13080 36502 36567 1278 | 13092 36438 36535 1279 | 13101 36389 36519 1280 | 13113 36358 36505 1281 | 13121 36345 36503 1282 | 13133 36322 36494 1283 | 13142 36298 36487 1284 | 13154 36284 36482 1285 | 13162 36273 36478 1286 | 13174 36256 36472 1287 | 13183 36245 36471 1288 | 13195 36221 36447 1289 | 13203 36223 36452 1290 | 13215 36225 36447 1291 | 13224 36206 36452 1292 | 13236 36208 36452 1293 | 13244 36200 36452 1294 | 13256 36210 36450 1295 | 13265 36208 36448 1296 | 13277 36217 36461 1297 | 13285 36236 36467 1298 | 13297 36270 36469 1299 | 13306 36281 36483 1300 | 13318 36291 36500 1301 | 13326 36336 36517 1302 | 13338 36332 36499 1303 | 13346 36348 36506 1304 | 13359 36347 36521 1305 | 13367 36352 36518 1306 | 13379 36350 36509 1307 | 13387 36348 36496 1308 | 13400 36341 36512 1309 | 13408 36342 36508 1310 | 13420 36332 36489 1311 | 13428 36325 36493 1312 | 13441 36317 36488 1313 | 13449 36344 36481 1314 | 13461 36315 36492 1315 | 13469 36335 36502 1316 | 13482 36337 36500 1317 | 13490 36347 36504 1318 | 13502 36369 36490 1319 | 13510 36377 36513 1320 | 13523 36375 36525 1321 | 13531 36379 36522 1322 | 13543 36402 36530 1323 | 13551 36409 36546 1324 | 13564 36444 36558 1325 | 13572 36433 36541 1326 | 13584 36446 36560 1327 | 13592 36468 36572 1328 | 13605 36483 36579 1329 | 13613 36498 36562 1330 | 13625 36511 36578 1331 | 13633 36527 36579 1332 | 13645 36560 36599 1333 | 13654 36565 36603 1334 | 13666 36579 36608 1335 | 13674 36597 36612 1336 | 13686 36601 36616 1337 | 13695 36606 36624 1338 | 13707 36635 36627 1339 | 13715 36645 36635 1340 | 13727 36670 36649 1341 | 13736 36676 36656 1342 | 13748 36697 36652 1343 | 13756 36711 36674 1344 | 13768 36721 36681 1345 | 13777 36737 36665 1346 | 13789 36747 36693 1347 | 13797 36769 36684 1348 | 13809 36808 36700 1349 | 13817 36821 36704 1350 | 13830 36833 36707 1351 | 13838 36853 36715 1352 | 13850 36867 36730 1353 | 13858 36891 36738 1354 | 13871 36887 36740 1355 | 13879 36903 36736 1356 | 13891 36908 36748 1357 | 13899 36929 36763 1358 | 13912 36934 36772 1359 | 13920 36940 36763 1360 | 13932 36946 36758 1361 | 13940 36948 36778 1362 | 13953 36961 36772 1363 | 13961 36981 36777 1364 | 13973 36963 36791 1365 | 13981 36998 36788 1366 | 13994 37011 36785 1367 | 14002 37014 36785 1368 | 14014 37024 36786 1369 | 14022 37032 36818 1370 | 14035 37044 36817 1371 | 14043 37055 36819 1372 | 14055 37064 36811 1373 | 14063 37067 36823 1374 | 14076 37089 36820 1375 | 14084 37078 36787 1376 | 14096 37050 36783 1377 | 14104 37008 36775 1378 | 14116 36949 36739 1379 | 14125 36884 36688 1380 | 14137 36792 36656 1381 | 14145 36703 36588 1382 | 14157 36603 36560 1383 | 14166 36521 36519 1384 | 14178 36394 36472 1385 | 14186 36339 36443 1386 | 14198 36296 36450 1387 | 14207 36276 36429 1388 | 14219 36264 36434 1389 | 14231 36237 36395 1390 | 14239 36236 36406 1391 | 14251 36219 36398 1392 | 14260 36200 36401 1393 | 14272 36184 36379 1394 | 14280 36192 36386 1395 | 14292 36182 36366 1396 | 14301 36172 36378 1397 | 14313 36172 36365 1398 | 14321 36155 36374 1399 | 14333 36171 36380 1400 | 14342 36174 36391 1401 | 14354 36190 36402 1402 | 14362 36225 36404 1403 | 14374 36235 36422 1404 | 14383 36266 36426 1405 | 14395 36285 36444 1406 | 14403 36297 36461 1407 | 14415 36327 36458 1408 | 14424 36329 36458 1409 | 14436 36355 36465 1410 | 14444 36363 36480 1411 | 14456 36366 36464 1412 | 14465 36357 36457 1413 | 14477 36358 36463 1414 | 14485 36355 36462 1415 | 14497 36362 36458 1416 | 14506 36353 36468 1417 | 14518 36336 36451 1418 | 14526 36338 36444 1419 | 14538 36336 36462 1420 | 14547 36346 36461 1421 | 14559 36367 36465 1422 | 14567 36365 36468 1423 | 14579 36369 36464 1424 | 14588 36402 36460 1425 | 14600 36395 36479 1426 | 14608 36415 36480 1427 | 14620 36418 36492 1428 | 14628 36430 36497 1429 | 14641 36434 36488 1430 | 14649 36445 36490 1431 | 14661 36466 36490 1432 | 14669 36458 36505 1433 | 14682 36483 36497 1434 | 14690 36495 36512 1435 | 14702 36507 36514 1436 | 14710 36517 36520 1437 | 14723 36524 36519 1438 | 14731 36551 36526 1439 | 14743 36550 36549 1440 | 14751 36559 36526 1441 | 14764 36579 36544 1442 | 14772 36579 36551 1443 | 14784 36615 36544 1444 | 14792 36602 36556 1445 | 14805 36631 36558 1446 | 14813 36624 36553 1447 | 14825 36621 36564 1448 | 14833 36644 36578 1449 | 14846 36634 36577 1450 | 14854 36655 36575 1451 | 14866 36677 36588 1452 | 14874 36681 36594 1453 | 14886 36685 36586 1454 | 14895 36696 36598 1455 | 14907 36695 36595 1456 | 14915 36710 36603 1457 | 14927 36727 36623 1458 | 14936 36741 36613 1459 | 14948 36747 36614 1460 | 14956 36771 36621 1461 | 14968 36776 36634 1462 | 14977 36794 36629 1463 | 14989 36810 36641 1464 | 14997 36826 36646 1465 | 15009 36828 36646 1466 | 15018 36844 36669 1467 | 15030 36860 36675 1468 | 15038 36879 36668 1469 | 15050 36882 36689 1470 | 15059 36907 36673 1471 | 15071 36901 36691 1472 | 15079 36896 36653 1473 | 15091 36878 36665 1474 | 15100 36819 36626 1475 | 15112 36761 36586 1476 | 15120 36690 36546 1477 | 15132 36606 36515 1478 | 15140 36514 36489 1479 | 15153 36449 36437 1480 | 15161 36353 36406 1481 | 15173 36293 36374 1482 | 15181 36253 36369 1483 | 15194 36205 36344 1484 | 15202 36177 36327 1485 | 15214 36148 36321 1486 | 15222 36129 36311 1487 | 15235 36118 36319 1488 | 15243 36118 36308 1489 | 15255 36104 36297 1490 | 15263 36099 36284 1491 | 15276 36093 36308 1492 | 15284 36084 36284 1493 | 15296 36084 36290 1494 | 15304 36086 36290 1495 | 15317 36084 36309 1496 | 15325 36109 36313 1497 | 15337 36118 36306 1498 | 15345 36141 36333 1499 | 15358 36180 36320 1500 | 15366 36209 36346 1501 | 15378 36228 36370 1502 | 15386 36250 36374 1503 | 15398 36278 36386 1504 | 15407 36294 36371 1505 | 15419 36291 36377 1506 | 15427 36297 36395 1507 | 15439 36318 36388 1508 | 15448 36310 36402 1509 | 15460 36325 36407 1510 | 15468 36338 36400 1511 | 15480 36334 36401 1512 | 15489 36333 36405 1513 | 15501 36345 36400 1514 | 15509 36324 36391 1515 | 15521 36340 36391 1516 | 15530 36347 36389 1517 | 15542 36331 36394 1518 | 15550 36335 36394 1519 | 15562 36332 36388 1520 | 15571 36353 36403 1521 | 15583 36388 36401 1522 | 15591 36362 36410 1523 | 15603 36390 36403 1524 | 15611 36398 36421 1525 | 15624 36406 36420 1526 | 15636 36415 36412 1527 | 15644 36441 36427 1528 | 15656 36474 36453 1529 | 15665 36488 36441 1530 | 15677 36502 36452 1531 | 15685 36532 36459 1532 | 15697 36533 36474 1533 | 15706 36542 36474 1534 | 15718 36556 36466 1535 | 15726 36563 36479 1536 | 15738 36566 36478 1537 | 15747 36577 36493 1538 | 15759 36604 36496 1539 | 15767 36615 36499 1540 | 15779 36615 36503 1541 | 15788 36637 36499 1542 | 15800 36644 36510 1543 | 15808 36653 36523 1544 | 15820 36651 36533 1545 | 15829 36681 36537 1546 | 15841 36696 36542 1547 | 15849 36703 36544 1548 | 15861 36733 36546 1549 | 15869 36739 36561 1550 | 15882 36768 36559 1551 | 15890 36777 36565 1552 | 15902 36791 36575 1553 | 15910 36794 36579 1554 | 15923 36799 36589 1555 | 15931 36812 36586 1556 | 15943 36832 36598 1557 | 15951 36853 36613 1558 | 15964 36859 36617 1559 | 15972 36864 36617 1560 | 15984 36865 36624 1561 | 15992 36878 36633 1562 | 16005 36905 36621 1563 | 16013 36911 36629 1564 | 16025 36920 36646 1565 | 16033 36948 36659 1566 | 16045 36950 36656 1567 | 16054 36969 36653 1568 | 16066 36973 36657 1569 | 16074 36970 36672 1570 | 16087 36986 36676 1571 | 16095 37000 36674 1572 | 16107 36989 36677 1573 | 16115 37002 36666 1574 | 16128 36969 36654 1575 | 16136 36950 36642 1576 | 16148 36885 36617 1577 | 16156 36824 36567 1578 | 16168 36727 36518 1579 | 16177 36633 36471 1580 | 16189 36526 36417 1581 | 16197 36446 36386 1582 | 16209 36350 36348 1583 | 16218 36288 36324 1584 | 16230 36226 36296 1585 | 16238 36194 36278 1586 | 16250 36140 36275 1587 | 16259 36122 36264 1588 | 16271 36097 36237 1589 | 16279 36081 36234 1590 | 16291 36062 36244 1591 | 16300 36041 36226 1592 | 16312 36054 36228 1593 | 16320 36046 36203 1594 | 16332 36023 36209 1595 | 16341 36012 36225 1596 | 16353 36014 36203 1597 | 16361 36011 36204 1598 | 16373 36006 36212 1599 | 16381 36015 36222 1600 | 16394 36039 36221 1601 | 16402 36075 36246 1602 | 16414 36097 36251 1603 | 16422 36110 36261 1604 | 16435 36153 36282 1605 | 16443 36171 36300 1606 | 16455 36201 36302 1607 | 16463 36210 36281 1608 | 16476 36209 36310 1609 | 16484 36220 36314 1610 | 16496 36240 36304 1611 | 16504 36246 36313 1612 | 16517 36245 36299 1613 | 16525 36244 36292 1614 | 16537 36253 36306 1615 | 16545 36227 36310 1616 | 16558 36242 36299 1617 | 16566 36223 36302 1618 | 16578 36221 36314 1619 | 16586 36233 36304 1620 | 16599 36226 36309 1621 | 16607 36245 36319 1622 | 16619 36257 36320 1623 | 16627 36263 36329 1624 | 16640 36265 36326 1625 | 16648 36278 36311 1626 | 16660 36293 36331 1627 | 16668 36297 36339 1628 | 16680 36313 36340 1629 | 16689 36326 36357 1630 | 16701 36327 36346 1631 | 16709 36345 36341 1632 | 16721 36354 36353 1633 | 16730 36373 36361 1634 | 16742 36379 36351 1635 | 16750 36419 36376 1636 | 16762 36432 36385 1637 | 16771 36435 36381 1638 | 16783 36455 36406 1639 | 16791 36456 36407 1640 | 16803 36470 36415 1641 | 16812 36479 36417 1642 | 16824 36498 36408 1643 | 16832 36517 36429 1644 | 16844 36529 36410 1645 | 16852 36538 36440 1646 | 16865 36540 36441 1647 | 16873 36555 36443 1648 | 16885 36573 36452 1649 | 16893 36582 36459 1650 | 16906 36587 36469 1651 | 16914 36593 36467 1652 | 16926 36602 36464 1653 | 16934 36609 36469 1654 | 16947 36628 36472 1655 | 16955 36639 36481 1656 | 16967 36655 36476 1657 | 16975 36654 36489 1658 | 16988 36672 36496 1659 | 17000 36680 36491 1660 | 17008 36688 36491 1661 | 17020 36700 36508 1662 | 17029 36695 36487 1663 | 17041 36710 36510 1664 | 17049 36714 36521 1665 | 17061 36732 36514 1666 | 17070 36741 36509 1667 | 17082 36746 36527 1668 | 17090 36749 36527 1669 | 17102 36763 36535 1670 | 17111 36776 36538 1671 | 17123 36802 36531 1672 | 17131 36813 36545 1673 | 17143 36809 36542 1674 | 17152 36815 36543 1675 | 17164 36843 36571 1676 | 17172 36848 36564 1677 | 17184 36854 36563 1678 | 17192 36860 36549 1679 | 17205 36801 36534 1680 | 17213 36771 36503 1681 | 17225 36708 36480 1682 | 17233 36617 36423 1683 | 17246 36507 36378 1684 | 17254 36412 36338 1685 | 17266 36346 36298 1686 | 17274 36238 36258 1687 | 17286 36153 36226 1688 | 17295 36082 36192 1689 | 17307 36034 36182 1690 | 17315 36006 36157 1691 | 17327 35949 36154 1692 | 17336 35944 36143 1693 | 17348 35912 36122 1694 | 17356 35896 36127 1695 | 17368 35890 36125 1696 | 17377 35868 36110 1697 | 17389 35848 36101 1698 | 17397 35862 36096 1699 | 17409 35841 36107 1700 | 17418 35836 36098 1701 | 17430 35840 36099 1702 | 17438 35838 36083 1703 | 17450 35833 36097 1704 | 17459 35842 36113 1705 | 17471 35855 36115 1706 | 17479 35871 36128 1707 | 17491 35938 36152 1708 | 17500 35962 36177 1709 | 17512 35989 36197 1710 | 17520 36022 36193 1711 | 17532 36041 36207 1712 | 17541 36064 36218 1713 | 17553 36084 36213 1714 | 17561 36101 36221 1715 | 17573 36104 36237 1716 | 17582 36110 36229 1717 | 17594 36120 36224 1718 | 17602 36118 36231 1719 | 17614 36126 36234 1720 | 17623 36121 36236 1721 | 17635 36120 36229 1722 | 17643 36125 36233 1723 | 17655 36127 36233 1724 | 17663 36131 36231 1725 | 17676 36118 36233 1726 | 17684 36132 36241 1727 | 17696 36147 36237 1728 | 17704 36151 36228 1729 | 17717 36166 36241 1730 | 17725 36189 36243 1731 | 17737 36212 36239 1732 | 17745 36222 36258 1733 | 17758 36212 36246 1734 | 17766 36233 36272 1735 | 17778 36252 36269 1736 | 17786 36261 36273 1737 | 17799 36294 36296 1738 | 17807 36299 36281 1739 | 17819 36327 36315 1740 | 17827 36340 36311 1741 | 17840 36352 36329 1742 | 17848 36357 36314 1743 | 17860 36368 36328 1744 | 17868 36393 36330 1745 | 17881 36410 36355 1746 | 17889 36432 36350 1747 | 17901 36439 36350 1748 | 17909 36458 36361 1749 | 17922 36473 36368 1750 | 17930 36482 36369 1751 | 17942 36494 36375 1752 | 17950 36512 36378 1753 | 17962 36519 36401 1754 | 17971 36530 36398 1755 | 17983 36545 36406 1756 | 17991 36565 36404 1757 | 18003 36596 36411 1758 | 18012 36605 36423 1759 | 18024 36589 36427 1760 | 18032 36614 36434 1761 | 18044 36612 36438 1762 | 18053 36615 36427 1763 | 18065 36646 36434 1764 | 18073 36641 36437 1765 | 18085 36649 36440 1766 | 18094 36661 36447 1767 | 18106 36674 36456 1768 | 18114 36702 36470 1769 | 18126 36709 36462 1770 | 18135 36727 36466 1771 | 18147 36754 36475 1772 | 18155 36748 36487 1773 | 18167 36756 36483 1774 | 18175 36751 36467 1775 | 18188 36739 36459 1776 | 18196 36688 36432 1777 | 18208 36620 36407 1778 | 18216 36541 36360 1779 | 18229 36340 36254 1780 | 18237 36223 36239 1781 | 18249 36148 36189 1782 | 18257 36064 36161 1783 | 18270 36000 36114 1784 | 18278 35939 36088 1785 | 18290 35897 36079 1786 | 18298 35857 36058 1787 | 18311 35833 36063 1788 | 18319 35818 36056 1789 | 18331 35809 36060 1790 | 18339 35798 36039 1791 | 18352 35792 36051 1792 | 18360 35772 36033 1793 | 18372 35777 36044 1794 | 18380 35769 36024 1795 | 18393 35764 36041 1796 | 18401 35764 36025 1797 | 18413 35762 36024 1798 | 18425 35776 36043 1799 | 18434 35801 36055 1800 | 18445 35822 36073 1801 | 18454 35838 36078 1802 | 18466 35871 36082 1803 | 18474 35880 36097 1804 | 18486 35912 36105 1805 | 18495 35942 36114 1806 | 18507 35960 36116 1807 | 18515 35975 36140 1808 | 18527 35986 36125 1809 | 18536 35982 36132 1810 | 18548 35993 36123 1811 | 18556 35985 36131 1812 | 18568 35979 36130 1813 | 18577 35977 36126 1814 | 18589 35967 36134 1815 | 18597 35955 36101 1816 | 18609 35956 36116 1817 | 18618 35941 36111 1818 | 18630 35953 36116 1819 | 18638 35971 36130 1820 | 18650 35959 36114 1821 | 18659 35964 36102 1822 | 18671 35969 36120 1823 | 18679 35976 36111 1824 | 18691 35983 36112 1825 | 18700 35990 36103 1826 | 18712 36011 36119 1827 | 18720 36018 36131 1828 | 18732 36041 36146 1829 | 18741 36039 36143 1830 | 18753 36051 36149 1831 | 18761 36068 36152 1832 | 18773 36074 36165 1833 | 18782 36085 36171 1834 | 18794 36093 36173 1835 | 18802 36117 36181 1836 | 18814 36134 36190 1837 | 18823 36145 36200 1838 | 18835 36160 36192 1839 | 18843 36170 36211 1840 | 18855 36171 36212 1841 | 18864 36193 36209 1842 | 18876 36208 36216 1843 | 18884 36222 36219 1844 | 18896 36246 36226 1845 | 18905 36255 36226 1846 | 18917 36249 36244 1847 | 18925 36270 36238 1848 | 18937 36281 36251 1849 | 18945 36298 36262 1850 | 18958 36309 36274 1851 | 18966 36319 36273 1852 | 18978 36320 36280 1853 | 18986 36329 36278 1854 | 18999 36346 36275 1855 | 19007 36357 36278 1856 | 19019 36377 36285 1857 | 19027 36380 36295 1858 | 19040 36394 36280 1859 | 19048 36412 36281 1860 | 19060 36434 36313 1861 | 19068 36423 36301 1862 | 19081 36420 36288 1863 | 19089 36400 36280 1864 | 19101 36344 36248 1865 | 19109 36276 36209 1866 | 19122 36185 36171 1867 | 19130 36074 36114 1868 | 19142 35969 36073 1869 | 19150 35870 36021 1870 | 19163 35775 35977 1871 | 19171 35683 35952 1872 | 19183 35623 35918 1873 | 19191 35570 35904 1874 | 19204 35534 35882 1875 | 19212 35505 35867 1876 | 19224 35470 35855 1877 | 19232 35451 35860 1878 | 19244 35450 35850 1879 | 19253 35429 35846 1880 | 19265 35420 35850 1881 | 19273 35432 35848 1882 | 19285 35426 35846 1883 | 19294 35409 35843 1884 | 19306 35404 35842 1885 | 19314 35383 35832 1886 | 19326 35415 35842 1887 | 19335 35441 35862 1888 | 19347 35447 35869 1889 | 19355 35486 35877 1890 | 19367 35522 35901 1891 | 19376 35549 35923 1892 | 19388 35586 35923 1893 | 19396 35612 35933 1894 | 19408 35650 35946 1895 | 19417 35667 35963 1896 | 19429 35672 35952 1897 | 19437 35694 35958 1898 | 19449 35709 35975 1899 | 19457 35713 35985 1900 | 19470 35709 35976 1901 | 19478 35716 35979 1902 | 19490 35696 35976 1903 | 19498 35701 35985 1904 | 19511 35698 35958 1905 | 19519 35692 35971 1906 | 19531 35714 35979 1907 | 19539 35696 35971 1908 | 19552 35718 35975 1909 | 19560 35695 35966 1910 | 19572 35711 35971 1911 | 19580 35709 35974 1912 | 19593 35720 35978 1913 | 19601 35746 35992 1914 | 19613 35745 35990 1915 | 19621 35754 36010 1916 | 19634 35786 36005 1917 | 19642 35795 36007 1918 | 19654 35799 36011 1919 | 19662 35814 36013 1920 | 19675 35837 36030 1921 | 19683 35855 36048 1922 | 19695 35869 36055 1923 | 19703 35892 36061 1924 | 19716 35911 36064 1925 | 19724 35906 36073 1926 | 19736 35933 36079 1927 | 19744 35937 36084 1928 | 19756 35965 36097 1929 | 19765 35979 36086 1930 | 19777 35989 36098 1931 | 19785 36005 36103 1932 | 19797 36023 36109 1933 | 19806 36042 36104 1934 | 19818 36045 36123 1935 | 19826 36062 36122 1936 | 19838 36058 36139 1937 | 19847 36084 36130 1938 | 19859 36085 36139 1939 | 19871 36112 36147 1940 | 19879 36127 36159 1941 | 19891 36129 36159 1942 | 19900 36139 36164 1943 | 19912 36157 36163 1944 | 19920 36175 36159 1945 | 19932 36167 36169 1946 | 19941 36168 36172 1947 | 19953 36203 36184 1948 | 19961 36209 36181 1949 | 19973 36204 36187 1950 | 19982 36232 36196 1951 | 19994 36238 36207 1952 | 20002 36245 36207 1953 | 20014 36267 36223 1954 | 20023 36276 36215 1955 | 20035 36271 36217 1956 | 20043 36278 36217 1957 | 20055 36271 36202 1958 | 20064 36283 36220 1959 | 20076 36237 36201 1960 | 20084 36189 36168 1961 | 20096 36120 36119 1962 | 20105 35994 36072 1963 | 20117 35899 36023 1964 | 20125 35775 35966 1965 | 20137 35649 35902 1966 | 20146 35540 35850 1967 | 20158 35461 35816 1968 | 20166 35368 35781 1969 | 20178 35317 35753 1970 | 20187 35259 35732 1971 | 20199 35222 35718 1972 | 20207 35192 35701 1973 | 20219 35180 35691 1974 | 20227 35149 35703 1975 | 20240 35130 35694 1976 | 20248 35124 35673 1977 | 20260 35136 35680 1978 | 20268 35111 35675 1979 | 20281 35092 35650 1980 | 20289 35099 35672 1981 | 20301 35098 35662 1982 | 20309 35091 35673 1983 | 20322 35100 35661 1984 | 20330 35105 35680 1985 | 20342 35124 35694 1986 | 20350 35142 35696 1987 | 20362 35189 35709 1988 | 20371 35216 35739 1989 | 20383 35235 35743 1990 | 20391 35263 35742 1991 | 20403 35285 35756 1992 | 20412 35308 35770 1993 | 20424 35334 35799 1994 | 20432 35369 35796 1995 | 20444 35370 35802 1996 | 20453 35389 35803 1997 | 20465 35391 35788 1998 | 20473 35385 35800 1999 | 20485 35382 35785 2000 | 20494 35369 35783 2001 | 20506 35358 35779 2002 | 20514 35375 35788 2003 | 20526 35373 35787 2004 | 20535 35363 35798 2005 | 20547 35396 35792 2006 | 20555 35415 35794 2007 | 20567 35433 35800 2008 | 20576 35430 35810 2009 | 20588 35443 35808 2010 | 20596 35468 35833 2011 | 20608 35470 35828 2012 | 20617 35489 35825 2013 | 20629 35513 35852 2014 | 20637 35543 35856 2015 | 20649 35561 35877 2016 | 20658 35590 35868 2017 | 20670 35599 35891 2018 | 20678 35629 35889 2019 | 20690 35645 35891 2020 | 20699 35660 35898 2021 | 20711 35683 35919 2022 | 20719 35693 35914 2023 | 20731 35710 35929 2024 | 20739 35706 35941 2025 | 20752 35712 35926 2026 | 20760 35734 35945 2027 | 20772 35751 35943 2028 | 20780 35759 35957 2029 | 20793 35775 35970 2030 | 20801 35782 35976 2031 | 20813 35792 35972 2032 | 20821 35797 35983 2033 | 20834 35822 35987 2034 | 20842 35819 35983 2035 | 20854 35831 35992 2036 | 20862 35849 35992 2037 | 20875 35838 36004 2038 | 20883 35863 35994 2039 | 20895 35866 36012 2040 | 20903 35874 36011 2041 | 20916 35881 36013 2042 | 20924 35891 36019 2043 | 20936 35901 36018 2044 | 20944 35912 36031 2045 | 20957 35920 36018 2046 | 20965 35930 36043 2047 | 20977 35936 36038 2048 | 20985 35951 36039 2049 | 20998 35964 36027 2050 | 21006 35978 36047 2051 | 21018 35987 36043 2052 | 21026 36004 36051 2053 | 21038 36010 36059 2054 | 21047 36031 36061 2055 | 21059 36031 36069 2056 | 21067 36040 36080 2057 | -------------------------------------------------------------------------------- /extras/rolling_graph/README.md: -------------------------------------------------------------------------------- 1 | # Rolling graph 2 | 3 | Graphs the filtered data from the sensor and overlays the beat detector stage, allowing 4 | a visual inspection of the beat detection algorithm. 5 | 6 | ## Requirements 7 | 8 | * Processing 3+ (http://www.processing.org) 9 | * Flash the example MAX30100_Debug to the target microcontroller 10 | 11 | ## Usage 12 | 13 | * Start processing and open the file rolling_graph.pde 14 | * If under linux or windows, adjust the line in order to match the serial port the microcontroller is connected to (eg: COM2, /dev/ttyUSB0). Under OSX the port should be autodetected. 15 | final String serialPort = "/dev/ttyACM0"; 16 | * Run the sketch 17 | 18 | ## Interpreting the screen 19 | 20 | Data coming from the sensor are plotted continuously. Legend for the time series: 21 | 22 | * Black graph (ch 0): infrared channel response level (the beat detector uses the IR channel) 23 | * Red graph (ch 1): beat detector threshold 24 | 25 | On the top left corner the following realtime values are printed: 26 | 27 | * channels 0 and 1 current, max and min values 28 | * computed heart rate 29 | * computed SpO2 30 | 31 | A typical working session would show a fairly regular black graph. Each peak of the black graph 32 | should be intercepted by the red graph. When this happens, the screen flashes red to signify 33 | that the beat detector is counting beats. 34 | 35 | If the red graph misses often one or more black peak, try to adjust the power of the IR LED. 36 | -------------------------------------------------------------------------------- /extras/rolling_graph/rolling_graph.pde: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | // Grapher helper for the Arduino MAX30100 library 20 | 21 | import processing.serial.*; 22 | 23 | // NOTE: when using PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES 24 | // set this to -1 to enable the auto range mode 25 | final int ABSMAX = 800; 26 | // Adjust to the serial port. Under OSX, UNO platforms and alike are auto-detected. 27 | final String serialPort = "/dev/tty.usbmodemFD13131"; 28 | 29 | 30 | final int WIDTH = 1200; 31 | final int HEIGHT = 600; 32 | final int CHANNELS = 2; 33 | final color[] colors = {color(0, 0, 0), color(255, 0, 0), color(0, 255, 0), color(0, 0, 255)}; 34 | 35 | 36 | float[][] series = new float[CHANNELS][WIDTH]; 37 | float heartRate = 0; 38 | int spO2 = 0; 39 | int redLedCurrentIndex = 0; 40 | boolean beatDetected = false; 41 | int ptr = 0; 42 | 43 | Serial myPort; 44 | 45 | void settings() 46 | { 47 | size(WIDTH, HEIGHT); 48 | } 49 | 50 | void setup () 51 | { 52 | String attemptPort = serialPort; 53 | 54 | for (int i=0 ; i < Serial.list().length ; ++i) { 55 | String port = Serial.list()[i]; 56 | if (port.matches(".+tty\\.usbmodem.+")) { 57 | attemptPort = port; 58 | break; 59 | } 60 | } 61 | 62 | println("Opening port " + attemptPort); 63 | 64 | myPort = new Serial(this, attemptPort, 115200); 65 | 66 | stroke(0); 67 | fill(0); 68 | textSize(8); 69 | } 70 | 71 | void draw () 72 | { 73 | if (beatDetected) { 74 | background(255, 200, 200); 75 | beatDetected = false; 76 | } else { 77 | background(255); 78 | } 79 | 80 | stroke(30); 81 | 82 | line(0, height/2, width, height/2); 83 | 84 | float maxv=0, minv; 85 | for (int s=0 ; s < CHANNELS ; ++s) { 86 | float[] samples = series[s]; 87 | maxv = max(maxv, abs(max(samples)), abs(min(samples))); 88 | if (ABSMAX != -1) { 89 | maxv = min(maxv, ABSMAX); 90 | } 91 | } 92 | 93 | // Avoids map() errors 94 | if (maxv == 0) { 95 | maxv = 1; 96 | } 97 | minv = -maxv; 98 | 99 | for (int s=0 ; s < CHANNELS ; ++s) { 100 | stroke(colors[s]); 101 | 102 | float[] samples = series[s]; 103 | float seriesMax = max(samples); 104 | 105 | text("ch " + s + " cur:" + samples[ptr] + " max:" + seriesMax + " min:" + min(samples), 0, 8 + 10 * s); 106 | 107 | boolean maxDisplayed = false; 108 | for (int i = 0 ; i < WIDTH ; ++i) { 109 | if (i > 0) { 110 | float ipy = HEIGHT - map(samples[i-1], minv, maxv, 0, HEIGHT); 111 | float iy = HEIGHT - map(samples[i], minv, maxv, 0, HEIGHT); 112 | 113 | if (abs(samples[i] - seriesMax) < 0.001 && !maxDisplayed) { 114 | text("v=" + samples[i], i, iy); 115 | maxDisplayed = true; 116 | } 117 | 118 | line(i - 1, ipy, i, iy); 119 | } 120 | } 121 | } 122 | 123 | text("Rate: " + heartRate, 200, 8); 124 | text("SpO2: " + spO2 + "%", 200, 18); 125 | text("RLI: " + redLedCurrentIndex, 200, 28); 126 | } 127 | 128 | void serialEvent (Serial myPort) 129 | { 130 | String sLine = myPort.readStringUntil('\n'); 131 | 132 | if (sLine == null) { 133 | return; 134 | } 135 | 136 | if (sLine.substring(0, 2).equals("R:")) { 137 | String[] sValues = split(sLine.substring(2), ','); 138 | 139 | for (int i=0 ; i < sValues.length ; ++i) { 140 | float sample = float(sValues[i]); 141 | 142 | if (Float.isNaN(sample)) { 143 | continue; 144 | } 145 | 146 | series[i][ptr] = sample; 147 | } 148 | 149 | ptr = (ptr + 1) % WIDTH; 150 | } else if (sLine.substring(0, 2).equals("H:")) { 151 | heartRate = float(sLine.substring(2)); 152 | } else if (sLine.substring(0, 2).equals("B:")) { 153 | beatDetected = true; 154 | } else if (sLine.substring(0, 2).equals("C:")) { 155 | println(sLine); 156 | } else if (sLine.substring(0, 2).equals("O:")) { 157 | spO2 = int(float(sLine.substring(2))); 158 | } else if (sLine.substring(0, 2).equals("I:")) { 159 | redLedCurrentIndex = int(float(sLine.substring(2))); 160 | } 161 | } -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MAX30100lib", 3 | "keywords": "pulse,oximetry,spo2,max30100,sensor,i2c", 4 | "description": "Maxim-IC MAX30100 heart-rate sensor driver and pulse-oximetry components", 5 | "authors": 6 | { 7 | "name": "OXullo Intersecans", 8 | "email": "x@brainrapers.org", 9 | "url": "https://github.com/oxullo/", 10 | "maintainer": true 11 | }, 12 | "repository": 13 | { 14 | "type": "git", 15 | "url": "https://github.com/oxullo/Arduino-MAX30100" 16 | }, 17 | "version": "1.2.1", 18 | "frameworks": "arduino", 19 | "platforms": "atmelavr" 20 | } 21 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=MAX30100lib 2 | version=1.2.1 3 | author=OXullo Intersecans 4 | maintainer=OXullo Intersecans 5 | sentence=Maxim-IC MAX30100 heart-rate sensor driver and pulse-oximetry components 6 | paragraph=This library exposes most of the features of the MAX30100 and offers a modular approach to calculate pulse rate and SpO2 7 | category=Sensors 8 | url=https://github.com/oxullo/Arduino-MAX30100 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/CircularBuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | CircularBuffer.h - Circular buffer library for Arduino. 3 | Copyright (c) 2017 Roberto Lo Giacco. 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, either version 3 of the 8 | License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | #ifndef __CIRCULAR_BUFFER__ 19 | #define __CIRCULAR_BUFFER__ 20 | #include 21 | 22 | #ifndef CIRCULAR_BUFFER_XS 23 | #define __CB_ST__ uint16_t 24 | #else 25 | #define __CB_ST__ uint8_t 26 | #endif 27 | 28 | #ifdef CIRCULAR_BUFFER_DEBUG 29 | #include 30 | #endif 31 | 32 | template class CircularBuffer { 33 | public: 34 | 35 | CircularBuffer(); 36 | 37 | ~CircularBuffer(); 38 | 39 | /** 40 | * Adds an element to the beginning of buffer: the operation returns `false` if the addition caused overwriting an existing element. 41 | */ 42 | bool unshift(T value); 43 | 44 | /** 45 | * Adds an element to the end of buffer: the operation returns `false` if the addition caused overwriting an existing element. 46 | */ 47 | bool push(T value); 48 | 49 | /** 50 | * Removes an element from the beginning of the buffer. 51 | */ 52 | T shift(); 53 | 54 | /** 55 | * Removes an element from the end of the buffer. 56 | */ 57 | T pop(); 58 | 59 | /** 60 | * Returns the element at the beginning of the buffer. 61 | */ 62 | T inline first(); 63 | 64 | /** 65 | * Returns the element at the end of the buffer. 66 | */ 67 | T inline last(); 68 | 69 | /** 70 | * Array-like access to buffer 71 | */ 72 | T operator [] (__CB_ST__ index); 73 | 74 | /** 75 | * Returns how many elements are actually stored in the buffer. 76 | */ 77 | __CB_ST__ inline size(); 78 | 79 | /** 80 | * Returns how many elements can be safely pushed into the buffer. 81 | */ 82 | __CB_ST__ inline available(); 83 | 84 | /** 85 | * Returns how many elements can be potentially stored into the buffer. 86 | */ 87 | __CB_ST__ inline capacity(); 88 | 89 | /** 90 | * Returns `true` if no elements can be removed from the buffer. 91 | */ 92 | bool inline isEmpty(); 93 | 94 | /** 95 | * Returns `true` if no elements can be added to the buffer without overwriting existing elements. 96 | */ 97 | bool inline isFull(); 98 | 99 | /** 100 | * Resets the buffer to a clean status, dropping any reference to current elements 101 | * and making all buffer positions available again. 102 | */ 103 | void inline clear(); 104 | 105 | #ifdef CIRCULAR_BUFFER_DEBUG 106 | void inline debug(Print* out); 107 | void inline debugFn(Print* out, void (*printFunction)(Print*, T)); 108 | #endif 109 | 110 | private: 111 | T buffer[S]; 112 | T *head; 113 | T *tail; 114 | uint16_t count; 115 | }; 116 | 117 | #include "CircularBuffer.tpp" 118 | #endif 119 | -------------------------------------------------------------------------------- /src/CircularBuffer.tpp: -------------------------------------------------------------------------------- 1 | /* 2 | CircularBuffer.tpp - Circular buffer library for Arduino. 3 | Copyright (c) 2017 Roberto Lo Giacco. 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as 7 | published by the Free Software Foundation, either version 3 of the 8 | License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | template 22 | CircularBuffer::CircularBuffer() : 23 | head(buffer), tail(buffer), count(0) { 24 | } 25 | 26 | template 27 | CircularBuffer::~CircularBuffer() { 28 | } 29 | 30 | template 31 | bool CircularBuffer::unshift(T value) { 32 | if (head == buffer) { 33 | head = buffer + S; 34 | } 35 | *--head = value; 36 | if (count == S) { 37 | if (tail-- == buffer) { 38 | tail = buffer + S - 1; 39 | } 40 | return false; 41 | } else { 42 | if (count++ == 0) { 43 | tail = head; 44 | } 45 | return true; 46 | } 47 | } 48 | 49 | template 50 | bool CircularBuffer::push(T value) { 51 | if (++tail == buffer + S) { 52 | tail = buffer; 53 | } 54 | *tail = value; 55 | if (count == S) { 56 | if (++head == buffer + S) { 57 | head = buffer; 58 | } 59 | return false; 60 | } else { 61 | if (count++ == 0) { 62 | head = tail; 63 | } 64 | return true; 65 | } 66 | } 67 | 68 | template 69 | T CircularBuffer::shift() { 70 | void(* crash) (void) = 0; 71 | if (count <= 0) crash(); 72 | T result = *head++; 73 | if (head >= buffer + S) { 74 | head = buffer; 75 | } 76 | count--; 77 | return result; 78 | } 79 | 80 | template 81 | T CircularBuffer::pop() { 82 | void(* crash) (void) = 0; 83 | if (count <= 0) crash(); 84 | T result = *tail--; 85 | if (tail < buffer) { 86 | tail = buffer + S - 1; 87 | } 88 | count--; 89 | return result; 90 | } 91 | 92 | template 93 | T inline CircularBuffer::first() { 94 | return *head; 95 | } 96 | 97 | template 98 | T inline CircularBuffer::last() { 99 | return *tail; 100 | } 101 | 102 | template 103 | T CircularBuffer::operator [](__CB_ST__ index) { 104 | return *(buffer + ((head - buffer + index) % S)); 105 | } 106 | 107 | template 108 | __CB_ST__ inline CircularBuffer::size() { 109 | return count; 110 | } 111 | 112 | template 113 | __CB_ST__ inline CircularBuffer::available() { 114 | return S - count; 115 | } 116 | 117 | template 118 | __CB_ST__ inline CircularBuffer::capacity() { 119 | return S; 120 | } 121 | 122 | template 123 | bool inline CircularBuffer::isEmpty() { 124 | return count == 0; 125 | } 126 | 127 | template 128 | bool inline CircularBuffer::isFull() { 129 | return count == S; 130 | } 131 | 132 | template 133 | void inline CircularBuffer::clear() { 134 | memset(buffer, 0, sizeof(buffer)); 135 | head = tail = buffer; 136 | count = 0; 137 | } 138 | 139 | #ifdef CIRCULAR_BUFFER_DEBUG 140 | template 141 | void inline CircularBuffer::debug(Print* out) { 142 | for (__CB_ST__ i = 0; i < S; i++) { 143 | int hex = (int)buffer + i; 144 | out->print(hex, HEX); 145 | out->print(" "); 146 | out->print(*(buffer + i)); 147 | if (head == buffer + i) { 148 | out->print(" head"); 149 | } 150 | if (tail == buffer + i) { 151 | out->print(" tail"); 152 | } 153 | out->println(); 154 | } 155 | } 156 | 157 | template 158 | void inline CircularBuffer::debugFn(Print* out, void (*printFunction)(Print*, T)) { 159 | for (__CB_ST__ i = 0; i < S; i++) { 160 | int hex = (int)buffer + i; 161 | out->print(hex, HEX); 162 | out->print(" "); 163 | printFunction(out, *(buffer + i)); 164 | if (head == buffer + i) { 165 | out->print(" head"); 166 | } 167 | if (tail == buffer + i) { 168 | out->print(" tail"); 169 | } 170 | out->println(); 171 | } 172 | } 173 | #endif -------------------------------------------------------------------------------- /src/MAX30100.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #include "MAX30100.h" 22 | 23 | MAX30100::MAX30100() 24 | { 25 | } 26 | 27 | bool MAX30100::begin() 28 | { 29 | Wire.begin(); 30 | Wire.setClock(I2C_BUS_SPEED); 31 | 32 | if (getPartId() != EXPECTED_PART_ID) { 33 | return false; 34 | } 35 | 36 | setMode(DEFAULT_MODE); 37 | setLedsPulseWidth(DEFAULT_PULSE_WIDTH); 38 | setSamplingRate(DEFAULT_SAMPLING_RATE); 39 | setLedsCurrent(DEFAULT_IR_LED_CURRENT, DEFAULT_RED_LED_CURRENT); 40 | setHighresModeEnabled(true); 41 | 42 | return true; 43 | } 44 | 45 | void MAX30100::setMode(Mode mode) 46 | { 47 | writeRegister(MAX30100_REG_MODE_CONFIGURATION, mode); 48 | } 49 | 50 | void MAX30100::setLedsPulseWidth(LEDPulseWidth ledPulseWidth) 51 | { 52 | uint8_t previous = readRegister(MAX30100_REG_SPO2_CONFIGURATION); 53 | writeRegister(MAX30100_REG_SPO2_CONFIGURATION, (previous & 0xfc) | ledPulseWidth); 54 | } 55 | 56 | void MAX30100::setSamplingRate(SamplingRate samplingRate) 57 | { 58 | uint8_t previous = readRegister(MAX30100_REG_SPO2_CONFIGURATION); 59 | writeRegister(MAX30100_REG_SPO2_CONFIGURATION, (previous & 0xe3) | (samplingRate << 2)); 60 | } 61 | 62 | void MAX30100::setLedsCurrent(LEDCurrent irLedCurrent, LEDCurrent redLedCurrent) 63 | { 64 | writeRegister(MAX30100_REG_LED_CONFIGURATION, redLedCurrent << 4 | irLedCurrent); 65 | } 66 | 67 | void MAX30100::setHighresModeEnabled(bool enabled) 68 | { 69 | uint8_t previous = readRegister(MAX30100_REG_SPO2_CONFIGURATION); 70 | if (enabled) { 71 | writeRegister(MAX30100_REG_SPO2_CONFIGURATION, previous | MAX30100_SPC_SPO2_HI_RES_EN); 72 | } else { 73 | writeRegister(MAX30100_REG_SPO2_CONFIGURATION, previous & ~MAX30100_SPC_SPO2_HI_RES_EN); 74 | } 75 | } 76 | 77 | void MAX30100::update() 78 | { 79 | readFifoData(); 80 | } 81 | 82 | bool MAX30100::getRawValues(uint16_t *ir, uint16_t *red) 83 | { 84 | if (!readoutsBuffer.isEmpty()) { 85 | SensorReadout readout = readoutsBuffer.pop(); 86 | 87 | *ir = readout.ir; 88 | *red = readout.red; 89 | 90 | return true; 91 | } else { 92 | return false; 93 | } 94 | } 95 | 96 | void MAX30100::resetFifo() 97 | { 98 | writeRegister(MAX30100_REG_FIFO_WRITE_POINTER, 0); 99 | writeRegister(MAX30100_REG_FIFO_READ_POINTER, 0); 100 | writeRegister(MAX30100_REG_FIFO_OVERFLOW_COUNTER, 0); 101 | } 102 | 103 | uint8_t MAX30100::readRegister(uint8_t address) 104 | { 105 | Wire.beginTransmission(MAX30100_I2C_ADDRESS); 106 | Wire.write(address); 107 | Wire.endTransmission(false); 108 | Wire.requestFrom(MAX30100_I2C_ADDRESS, 1); 109 | 110 | return Wire.read(); 111 | } 112 | 113 | void MAX30100::writeRegister(uint8_t address, uint8_t data) 114 | { 115 | Wire.beginTransmission(MAX30100_I2C_ADDRESS); 116 | Wire.write(address); 117 | Wire.write(data); 118 | Wire.endTransmission(); 119 | } 120 | 121 | void MAX30100::burstRead(uint8_t baseAddress, uint8_t *buffer, uint8_t length) 122 | { 123 | Wire.beginTransmission(MAX30100_I2C_ADDRESS); 124 | Wire.write(baseAddress); 125 | Wire.endTransmission(false); 126 | Wire.requestFrom((uint8_t)MAX30100_I2C_ADDRESS, length); 127 | 128 | uint8_t idx = 0; 129 | while (Wire.available()) { 130 | buffer[idx++] = Wire.read(); 131 | } 132 | } 133 | 134 | void MAX30100::readFifoData() 135 | { 136 | uint8_t buffer[MAX30100_FIFO_DEPTH*4]; 137 | uint8_t toRead; 138 | 139 | toRead = (readRegister(MAX30100_REG_FIFO_WRITE_POINTER) - readRegister(MAX30100_REG_FIFO_READ_POINTER)) & (MAX30100_FIFO_DEPTH-1); 140 | 141 | if (toRead) { 142 | burstRead(MAX30100_REG_FIFO_DATA, buffer, 4 * toRead); 143 | 144 | for (uint8_t i=0 ; i < toRead ; ++i) { 145 | // Warning: the values are always left-aligned 146 | readoutsBuffer.push({ 147 | .ir=(uint16_t)((buffer[i*4] << 8) | buffer[i*4 + 1]), 148 | .red=(uint16_t)((buffer[i*4 + 2] << 8) | buffer[i*4 + 3])}); 149 | } 150 | } 151 | } 152 | 153 | void MAX30100::startTemperatureSampling() 154 | { 155 | uint8_t modeConfig = readRegister(MAX30100_REG_MODE_CONFIGURATION); 156 | modeConfig |= MAX30100_MC_TEMP_EN; 157 | 158 | writeRegister(MAX30100_REG_MODE_CONFIGURATION, modeConfig); 159 | } 160 | 161 | bool MAX30100::isTemperatureReady() 162 | { 163 | return !(readRegister(MAX30100_REG_MODE_CONFIGURATION) & MAX30100_MC_TEMP_EN); 164 | } 165 | 166 | float MAX30100::retrieveTemperature() 167 | { 168 | int8_t tempInteger = readRegister(MAX30100_REG_TEMPERATURE_DATA_INT); 169 | float tempFrac = readRegister(MAX30100_REG_TEMPERATURE_DATA_FRAC); 170 | 171 | return tempFrac * 0.0625 + tempInteger; 172 | } 173 | 174 | void MAX30100::shutdown() 175 | { 176 | uint8_t modeConfig = readRegister(MAX30100_REG_MODE_CONFIGURATION); 177 | modeConfig |= MAX30100_MC_SHDN; 178 | 179 | writeRegister(MAX30100_REG_MODE_CONFIGURATION, modeConfig); 180 | } 181 | 182 | void MAX30100::resume() 183 | { 184 | uint8_t modeConfig = readRegister(MAX30100_REG_MODE_CONFIGURATION); 185 | modeConfig &= ~MAX30100_MC_SHDN; 186 | 187 | writeRegister(MAX30100_REG_MODE_CONFIGURATION, modeConfig); 188 | } 189 | 190 | uint8_t MAX30100::getPartId() 191 | { 192 | return readRegister(0xff); 193 | } 194 | -------------------------------------------------------------------------------- /src/MAX30100.h: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef MAX30100_H 20 | #define MAX30100_H 21 | 22 | #include 23 | 24 | #define CIRCULAR_BUFFER_XS 25 | #include "CircularBuffer.h" 26 | #include "MAX30100_Registers.h" 27 | 28 | #define DEFAULT_MODE MAX30100_MODE_HRONLY 29 | #define DEFAULT_SAMPLING_RATE MAX30100_SAMPRATE_100HZ 30 | #define DEFAULT_PULSE_WIDTH MAX30100_SPC_PW_1600US_16BITS 31 | #define DEFAULT_RED_LED_CURRENT MAX30100_LED_CURR_50MA 32 | #define DEFAULT_IR_LED_CURRENT MAX30100_LED_CURR_50MA 33 | #define EXPECTED_PART_ID 0x11 34 | #define RINGBUFFER_SIZE 16 35 | 36 | #define I2C_BUS_SPEED 400000UL 37 | 38 | typedef struct { 39 | uint16_t ir; 40 | uint16_t red; 41 | } SensorReadout; 42 | 43 | class MAX30100 { 44 | public: 45 | MAX30100(); 46 | bool begin(); 47 | void setMode(Mode mode); 48 | void setLedsPulseWidth(LEDPulseWidth ledPulseWidth); 49 | void setSamplingRate(SamplingRate samplingRate); 50 | void setLedsCurrent(LEDCurrent irLedCurrent, LEDCurrent redLedCurrent); 51 | void setHighresModeEnabled(bool enabled); 52 | void update(); 53 | bool getRawValues(uint16_t *ir, uint16_t *red); 54 | void resetFifo(); 55 | void startTemperatureSampling(); 56 | bool isTemperatureReady(); 57 | float retrieveTemperature(); 58 | void shutdown(); 59 | void resume(); 60 | uint8_t getPartId(); 61 | 62 | private: 63 | CircularBuffer readoutsBuffer; 64 | 65 | uint8_t readRegister(uint8_t address); 66 | void writeRegister(uint8_t address, uint8_t data); 67 | void burstRead(uint8_t baseAddress, uint8_t *buffer, uint8_t length); 68 | void readFifoData(); 69 | }; 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/MAX30100_BeatDetector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #include "MAX30100_BeatDetector.h" 22 | 23 | #ifndef min 24 | #define min(a,b) \ 25 | ({ __typeof__ (a) _a = (a); \ 26 | __typeof__ (b) _b = (b); \ 27 | _a < _b ? _a : _b; }) 28 | #endif 29 | 30 | BeatDetector::BeatDetector() : 31 | state(BEATDETECTOR_STATE_INIT), 32 | threshold(BEATDETECTOR_MIN_THRESHOLD), 33 | beatPeriod(0), 34 | lastMaxValue(0), 35 | tsLastBeat(0) 36 | { 37 | } 38 | 39 | bool BeatDetector::addSample(float sample) 40 | { 41 | return checkForBeat(sample); 42 | } 43 | 44 | float BeatDetector::getRate() 45 | { 46 | if (beatPeriod != 0) { 47 | return 1 / beatPeriod * 1000 * 60; 48 | } else { 49 | return 0; 50 | } 51 | } 52 | 53 | float BeatDetector::getCurrentThreshold() 54 | { 55 | return threshold; 56 | } 57 | 58 | bool BeatDetector::checkForBeat(float sample) 59 | { 60 | bool beatDetected = false; 61 | 62 | switch (state) { 63 | case BEATDETECTOR_STATE_INIT: 64 | if (millis() > BEATDETECTOR_INIT_HOLDOFF) { 65 | state = BEATDETECTOR_STATE_WAITING; 66 | } 67 | break; 68 | 69 | case BEATDETECTOR_STATE_WAITING: 70 | if (sample > threshold) { 71 | threshold = min(sample, BEATDETECTOR_MAX_THRESHOLD); 72 | state = BEATDETECTOR_STATE_FOLLOWING_SLOPE; 73 | } 74 | 75 | // Tracking lost, resetting 76 | if (millis() - tsLastBeat > BEATDETECTOR_INVALID_READOUT_DELAY) { 77 | beatPeriod = 0; 78 | lastMaxValue = 0; 79 | } 80 | 81 | decreaseThreshold(); 82 | break; 83 | 84 | case BEATDETECTOR_STATE_FOLLOWING_SLOPE: 85 | if (sample < threshold) { 86 | state = BEATDETECTOR_STATE_MAYBE_DETECTED; 87 | } else { 88 | threshold = min(sample, BEATDETECTOR_MAX_THRESHOLD); 89 | } 90 | break; 91 | 92 | case BEATDETECTOR_STATE_MAYBE_DETECTED: 93 | if (sample + BEATDETECTOR_STEP_RESILIENCY < threshold) { 94 | // Found a beat 95 | beatDetected = true; 96 | lastMaxValue = sample; 97 | state = BEATDETECTOR_STATE_MASKING; 98 | float delta = millis() - tsLastBeat; 99 | if (delta) { 100 | beatPeriod = BEATDETECTOR_BPFILTER_ALPHA * delta + 101 | (1 - BEATDETECTOR_BPFILTER_ALPHA) * beatPeriod; 102 | } 103 | 104 | tsLastBeat = millis(); 105 | } else { 106 | state = BEATDETECTOR_STATE_FOLLOWING_SLOPE; 107 | } 108 | break; 109 | 110 | case BEATDETECTOR_STATE_MASKING: 111 | if (millis() - tsLastBeat > BEATDETECTOR_MASKING_HOLDOFF) { 112 | state = BEATDETECTOR_STATE_WAITING; 113 | } 114 | decreaseThreshold(); 115 | break; 116 | } 117 | 118 | return beatDetected; 119 | } 120 | 121 | void BeatDetector::decreaseThreshold() 122 | { 123 | // When a valid beat rate readout is present, target the 124 | if (lastMaxValue > 0 && beatPeriod > 0) { 125 | threshold -= lastMaxValue * (1 - BEATDETECTOR_THRESHOLD_FALLOFF_TARGET) / 126 | (beatPeriod / BEATDETECTOR_SAMPLES_PERIOD); 127 | } else { 128 | // Asymptotic decay 129 | threshold *= BEATDETECTOR_THRESHOLD_DECAY_FACTOR; 130 | } 131 | 132 | if (threshold < BEATDETECTOR_MIN_THRESHOLD) { 133 | threshold = BEATDETECTOR_MIN_THRESHOLD; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/MAX30100_BeatDetector.h: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef MAX30100_BEATDETECTOR_H 20 | #define MAX30100_BEATDETECTOR_H 21 | 22 | #include 23 | 24 | #define BEATDETECTOR_INIT_HOLDOFF 2000 // in ms, how long to wait before counting 25 | #define BEATDETECTOR_MASKING_HOLDOFF 200 // in ms, non-retriggerable window after beat detection 26 | #define BEATDETECTOR_BPFILTER_ALPHA 0.6 // EMA factor for the beat period value 27 | #define BEATDETECTOR_MIN_THRESHOLD 20 // minimum threshold (filtered) value 28 | #define BEATDETECTOR_MAX_THRESHOLD 800 // maximum threshold (filtered) value 29 | #define BEATDETECTOR_STEP_RESILIENCY 30 // maximum negative jump that triggers the beat edge 30 | #define BEATDETECTOR_THRESHOLD_FALLOFF_TARGET 0.3 // thr chasing factor of the max value when beat 31 | #define BEATDETECTOR_THRESHOLD_DECAY_FACTOR 0.99 // thr chasing factor when no beat 32 | #define BEATDETECTOR_INVALID_READOUT_DELAY 2000 // in ms, no-beat time to cause a reset 33 | #define BEATDETECTOR_SAMPLES_PERIOD 10 // in ms, 1/Fs 34 | 35 | 36 | typedef enum BeatDetectorState { 37 | BEATDETECTOR_STATE_INIT, 38 | BEATDETECTOR_STATE_WAITING, 39 | BEATDETECTOR_STATE_FOLLOWING_SLOPE, 40 | BEATDETECTOR_STATE_MAYBE_DETECTED, 41 | BEATDETECTOR_STATE_MASKING 42 | } BeatDetectorState; 43 | 44 | 45 | class BeatDetector 46 | { 47 | public: 48 | BeatDetector(); 49 | bool addSample(float sample); 50 | float getRate(); 51 | float getCurrentThreshold(); 52 | 53 | private: 54 | bool checkForBeat(float value); 55 | void decreaseThreshold(); 56 | 57 | BeatDetectorState state; 58 | float threshold; 59 | float beatPeriod; 60 | float lastMaxValue; 61 | uint32_t tsLastBeat; 62 | }; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/MAX30100_Filters.h: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef MAX30100_FILTERS_H 20 | #define MAX30100_FILTERS_H 21 | 22 | // http://www.schwietering.com/jayduino/filtuino/ 23 | // Low pass butterworth filter order=1 alpha1=0.1 24 | // Fs=100Hz, Fc=6Hz 25 | class FilterBuLp1 26 | { 27 | public: 28 | FilterBuLp1() 29 | { 30 | v[0]=0.0; 31 | } 32 | private: 33 | float v[2]; 34 | public: 35 | float step(float x) //class II 36 | { 37 | v[0] = v[1]; 38 | v[1] = (2.452372752527856026e-1 * x) 39 | + (0.50952544949442879485 * v[0]); 40 | return 41 | (v[0] + v[1]); 42 | } 43 | }; 44 | 45 | // http://sam-koblenski.blogspot.de/2015/11/everyday-dsp-for-programmers-dc-and.html 46 | class DCRemover 47 | { 48 | public: 49 | DCRemover() : alpha(0), dcw(0) 50 | { 51 | } 52 | DCRemover(float alpha_) : alpha(alpha_), dcw(0) 53 | { 54 | } 55 | 56 | float step(float x) 57 | { 58 | float olddcw = dcw; 59 | dcw = (float)x + alpha * dcw; 60 | 61 | return dcw - olddcw; 62 | } 63 | 64 | float getDCW() 65 | { 66 | return dcw; 67 | } 68 | 69 | private: 70 | float alpha; 71 | float dcw; 72 | }; 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /src/MAX30100_PulseOximeter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #include "MAX30100_PulseOximeter.h" 22 | 23 | 24 | PulseOximeter::PulseOximeter() : 25 | state(PULSEOXIMETER_STATE_INIT), 26 | tsFirstBeatDetected(0), 27 | tsLastBeatDetected(0), 28 | tsLastBiasCheck(0), 29 | tsLastCurrentAdjustment(0), 30 | redLedCurrentIndex((uint8_t)RED_LED_CURRENT_START), 31 | irLedCurrent(DEFAULT_IR_LED_CURRENT), 32 | onBeatDetected(NULL) 33 | { 34 | } 35 | 36 | bool PulseOximeter::begin(PulseOximeterDebuggingMode debuggingMode_) 37 | { 38 | debuggingMode = debuggingMode_; 39 | 40 | bool ready = hrm.begin(); 41 | 42 | if (!ready) { 43 | if (debuggingMode != PULSEOXIMETER_DEBUGGINGMODE_NONE) { 44 | Serial.println("Failed to initialize the HRM sensor"); 45 | } 46 | return false; 47 | } 48 | 49 | hrm.setMode(MAX30100_MODE_SPO2_HR); 50 | hrm.setLedsCurrent(irLedCurrent, (LEDCurrent)redLedCurrentIndex); 51 | 52 | irDCRemover = DCRemover(DC_REMOVER_ALPHA); 53 | redDCRemover = DCRemover(DC_REMOVER_ALPHA); 54 | 55 | state = PULSEOXIMETER_STATE_IDLE; 56 | 57 | return true; 58 | } 59 | 60 | void PulseOximeter::update() 61 | { 62 | hrm.update(); 63 | 64 | checkSample(); 65 | checkCurrentBias(); 66 | } 67 | 68 | float PulseOximeter::getHeartRate() 69 | { 70 | return beatDetector.getRate(); 71 | } 72 | 73 | uint8_t PulseOximeter::getSpO2() 74 | { 75 | return spO2calculator.getSpO2(); 76 | } 77 | 78 | uint8_t PulseOximeter::getRedLedCurrentBias() 79 | { 80 | return redLedCurrentIndex; 81 | } 82 | 83 | void PulseOximeter::setOnBeatDetectedCallback(void (*cb)()) 84 | { 85 | onBeatDetected = cb; 86 | } 87 | 88 | void PulseOximeter::setIRLedCurrent(LEDCurrent irLedNewCurrent) 89 | { 90 | irLedCurrent = irLedNewCurrent; 91 | hrm.setLedsCurrent(irLedCurrent, (LEDCurrent)redLedCurrentIndex); 92 | } 93 | 94 | void PulseOximeter::shutdown() 95 | { 96 | hrm.shutdown(); 97 | } 98 | 99 | void PulseOximeter::resume() 100 | { 101 | hrm.resume(); 102 | } 103 | 104 | void PulseOximeter::checkSample() 105 | { 106 | uint16_t rawIRValue, rawRedValue; 107 | 108 | // Dequeue all available samples, they're properly timed by the HRM 109 | while (hrm.getRawValues(&rawIRValue, &rawRedValue)) { 110 | float irACValue = irDCRemover.step(rawIRValue); 111 | float redACValue = redDCRemover.step(rawRedValue); 112 | 113 | // The signal fed to the beat detector is mirrored since the cleanest monotonic spike is below zero 114 | float filteredPulseValue = lpf.step(-irACValue); 115 | bool beatDetected = beatDetector.addSample(filteredPulseValue); 116 | 117 | if (beatDetector.getRate() > 0) { 118 | state = PULSEOXIMETER_STATE_DETECTING; 119 | spO2calculator.update(irACValue, redACValue, beatDetected); 120 | } else if (state == PULSEOXIMETER_STATE_DETECTING) { 121 | state = PULSEOXIMETER_STATE_IDLE; 122 | spO2calculator.reset(); 123 | } 124 | 125 | switch (debuggingMode) { 126 | case PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES: 127 | Serial.print("R:"); 128 | Serial.print(rawIRValue); 129 | Serial.print(","); 130 | Serial.println(rawRedValue); 131 | break; 132 | 133 | case PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES: 134 | Serial.print("R:"); 135 | Serial.print(irACValue); 136 | Serial.print(","); 137 | Serial.println(redACValue); 138 | break; 139 | 140 | case PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT: 141 | Serial.print("R:"); 142 | Serial.print(filteredPulseValue); 143 | Serial.print(","); 144 | Serial.println(beatDetector.getCurrentThreshold()); 145 | break; 146 | 147 | default: 148 | break; 149 | } 150 | 151 | if (beatDetected && onBeatDetected) { 152 | onBeatDetected(); 153 | } 154 | } 155 | } 156 | 157 | void PulseOximeter::checkCurrentBias() 158 | { 159 | // Follower that adjusts the red led current in order to have comparable DC baselines between 160 | // red and IR leds. The numbers are really magic: the less possible to avoid oscillations 161 | if (millis() - tsLastBiasCheck > CURRENT_ADJUSTMENT_PERIOD_MS) { 162 | bool changed = false; 163 | if (irDCRemover.getDCW() - redDCRemover.getDCW() > 70000 && redLedCurrentIndex < MAX30100_LED_CURR_50MA) { 164 | ++redLedCurrentIndex; 165 | changed = true; 166 | } else if (redDCRemover.getDCW() - irDCRemover.getDCW() > 70000 && redLedCurrentIndex > 0) { 167 | --redLedCurrentIndex; 168 | changed = true; 169 | } 170 | 171 | if (changed) { 172 | hrm.setLedsCurrent(irLedCurrent, (LEDCurrent)redLedCurrentIndex); 173 | tsLastCurrentAdjustment = millis(); 174 | 175 | if (debuggingMode != PULSEOXIMETER_DEBUGGINGMODE_NONE) { 176 | Serial.print("I:"); 177 | Serial.println(redLedCurrentIndex); 178 | } 179 | } 180 | 181 | tsLastBiasCheck = millis(); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/MAX30100_PulseOximeter.h: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef MAX30100_PULSEOXIMETER_H 20 | #define MAX30100_PULSEOXIMETER_H 21 | 22 | #define SAMPLING_FREQUENCY 100 23 | #define CURRENT_ADJUSTMENT_PERIOD_MS 500 24 | #define DEFAULT_IR_LED_CURRENT MAX30100_LED_CURR_50MA 25 | #define RED_LED_CURRENT_START MAX30100_LED_CURR_27_1MA 26 | #define DC_REMOVER_ALPHA 0.95 27 | 28 | #include 29 | 30 | #include "MAX30100.h" 31 | #include "MAX30100_BeatDetector.h" 32 | #include "MAX30100_Filters.h" 33 | #include "MAX30100_SpO2Calculator.h" 34 | 35 | typedef enum PulseOximeterState { 36 | PULSEOXIMETER_STATE_INIT, 37 | PULSEOXIMETER_STATE_IDLE, 38 | PULSEOXIMETER_STATE_DETECTING 39 | } PulseOximeterState; 40 | 41 | typedef enum PulseOximeterDebuggingMode { 42 | PULSEOXIMETER_DEBUGGINGMODE_NONE, 43 | PULSEOXIMETER_DEBUGGINGMODE_RAW_VALUES, 44 | PULSEOXIMETER_DEBUGGINGMODE_AC_VALUES, 45 | PULSEOXIMETER_DEBUGGINGMODE_PULSEDETECT 46 | } PulseOximeterDebuggingMode; 47 | 48 | 49 | class PulseOximeter { 50 | public: 51 | PulseOximeter(); 52 | 53 | bool begin(PulseOximeterDebuggingMode debuggingMode_=PULSEOXIMETER_DEBUGGINGMODE_NONE); 54 | void update(); 55 | float getHeartRate(); 56 | uint8_t getSpO2(); 57 | uint8_t getRedLedCurrentBias(); 58 | void setOnBeatDetectedCallback(void (*cb)()); 59 | void setIRLedCurrent(LEDCurrent irLedCurrent); 60 | void shutdown(); 61 | void resume(); 62 | 63 | private: 64 | void checkSample(); 65 | void checkCurrentBias(); 66 | 67 | PulseOximeterState state; 68 | PulseOximeterDebuggingMode debuggingMode; 69 | uint32_t tsFirstBeatDetected; 70 | uint32_t tsLastBeatDetected; 71 | uint32_t tsLastBiasCheck; 72 | uint32_t tsLastCurrentAdjustment; 73 | BeatDetector beatDetector; 74 | DCRemover irDCRemover; 75 | DCRemover redDCRemover; 76 | FilterBuLp1 lpf; 77 | uint8_t redLedCurrentIndex; 78 | LEDCurrent irLedCurrent; 79 | SpO2Calculator spO2calculator; 80 | MAX30100 hrm; 81 | 82 | void (*onBeatDetected)(); 83 | }; 84 | #endif 85 | -------------------------------------------------------------------------------- /src/MAX30100_Registers.h: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef MAX30100_REGISTERS_H 20 | #define MAX30100_REGISTERS_H 21 | 22 | #define MAX30100_I2C_ADDRESS 0x57 23 | 24 | // Interrupt status register (RO) 25 | #define MAX30100_REG_INTERRUPT_STATUS 0x00 26 | #define MAX30100_IS_PWR_RDY (1 << 0) 27 | #define MAX30100_IS_SPO2_RDY (1 << 4) 28 | #define MAX30100_IS_HR_RDY (1 << 5) 29 | #define MAX30100_IS_TEMP_RDY (1 << 6) 30 | #define MAX30100_IS_A_FULL (1 << 7) 31 | 32 | // Interrupt enable register 33 | #define MAX30100_REG_INTERRUPT_ENABLE 0x01 34 | #define MAX30100_IE_ENB_SPO2_RDY (1 << 4) 35 | #define MAX30100_IE_ENB_HR_RDY (1 << 5) 36 | #define MAX30100_IE_ENB_TEMP_RDY (1 << 6) 37 | #define MAX30100_IE_ENB_A_FULL (1 << 7) 38 | 39 | // FIFO control and data registers 40 | #define MAX30100_REG_FIFO_WRITE_POINTER 0x02 41 | #define MAX30100_REG_FIFO_OVERFLOW_COUNTER 0x03 42 | #define MAX30100_REG_FIFO_READ_POINTER 0x04 43 | #define MAX30100_REG_FIFO_DATA 0x05 // Burst read does not autoincrement addr 44 | 45 | // Mode Configuration register 46 | #define MAX30100_REG_MODE_CONFIGURATION 0x06 47 | #define MAX30100_MC_TEMP_EN (1 << 3) 48 | #define MAX30100_MC_RESET (1 << 6) 49 | #define MAX30100_MC_SHDN (1 << 7) 50 | typedef enum Mode { 51 | MAX30100_MODE_HRONLY = 0x02, 52 | MAX30100_MODE_SPO2_HR = 0x03 53 | } Mode; 54 | 55 | // SpO2 Configuration register 56 | // Check tables 8 and 9, p19 of the MAX30100 datasheet to see the permissible 57 | // combinations of sampling rates and pulse widths 58 | #define MAX30100_REG_SPO2_CONFIGURATION 0x07 59 | #define MAX30100_SPC_SPO2_HI_RES_EN (1 << 6) 60 | typedef enum SamplingRate { 61 | MAX30100_SAMPRATE_50HZ = 0x00, 62 | MAX30100_SAMPRATE_100HZ = 0x01, 63 | MAX30100_SAMPRATE_167HZ = 0x02, 64 | MAX30100_SAMPRATE_200HZ = 0x03, 65 | MAX30100_SAMPRATE_400HZ = 0x04, 66 | MAX30100_SAMPRATE_600HZ = 0x05, 67 | MAX30100_SAMPRATE_800HZ = 0x06, 68 | MAX30100_SAMPRATE_1000HZ = 0x07 69 | } SamplingRate; 70 | 71 | typedef enum LEDPulseWidth { 72 | MAX30100_SPC_PW_200US_13BITS = 0x00, 73 | MAX30100_SPC_PW_400US_14BITS = 0x01, 74 | MAX30100_SPC_PW_800US_15BITS = 0x02, 75 | MAX30100_SPC_PW_1600US_16BITS = 0x03 76 | } LEDPulseWidth; 77 | 78 | // LED Configuration register 79 | #define MAX30100_REG_LED_CONFIGURATION 0x09 80 | typedef enum LEDCurrent { 81 | MAX30100_LED_CURR_0MA = 0x00, 82 | MAX30100_LED_CURR_4_4MA = 0x01, 83 | MAX30100_LED_CURR_7_6MA = 0x02, 84 | MAX30100_LED_CURR_11MA = 0x03, 85 | MAX30100_LED_CURR_14_2MA = 0x04, 86 | MAX30100_LED_CURR_17_4MA = 0x05, 87 | MAX30100_LED_CURR_20_8MA = 0x06, 88 | MAX30100_LED_CURR_24MA = 0x07, 89 | MAX30100_LED_CURR_27_1MA = 0x08, 90 | MAX30100_LED_CURR_30_6MA = 0x09, 91 | MAX30100_LED_CURR_33_8MA = 0x0a, 92 | MAX30100_LED_CURR_37MA = 0x0b, 93 | MAX30100_LED_CURR_40_2MA = 0x0c, 94 | MAX30100_LED_CURR_43_6MA = 0x0d, 95 | MAX30100_LED_CURR_46_8MA = 0x0e, 96 | MAX30100_LED_CURR_50MA = 0x0f 97 | } LEDCurrent; 98 | 99 | // Temperature integer part register 100 | #define MAX30100_REG_TEMPERATURE_DATA_INT 0x16 101 | // Temperature fractional part register 102 | #define MAX30100_REG_TEMPERATURE_DATA_FRAC 0x17 103 | 104 | // Revision ID register (RO) 105 | #define MAX30100_REG_REVISION_ID 0xfe 106 | // Part ID register 107 | #define MAX30100_REG_PART_ID 0xff 108 | 109 | #define MAX30100_FIFO_DEPTH 0x10 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /src/MAX30100_SpO2Calculator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | 21 | #include "MAX30100_SpO2Calculator.h" 22 | 23 | // SaO2 Look-up Table 24 | // http://www.ti.com/lit/an/slaa274b/slaa274b.pdf 25 | const uint8_t SpO2Calculator::spO2LUT[43] = {100,100,100,100,99,99,99,99,99,99,98,98,98,98, 26 | 98,97,97,97,97,97,97,96,96,96,96,96,96,95,95, 27 | 95,95,95,95,94,94,94,94,94,93,93,93,93,93}; 28 | 29 | SpO2Calculator::SpO2Calculator() : 30 | irACValueSqSum(0), 31 | redACValueSqSum(0), 32 | beatsDetectedNum(0), 33 | samplesRecorded(0), 34 | spO2(0) 35 | { 36 | } 37 | 38 | void SpO2Calculator::update(float irACValue, float redACValue, bool beatDetected) 39 | { 40 | irACValueSqSum += irACValue * irACValue; 41 | redACValueSqSum += redACValue * redACValue; 42 | ++samplesRecorded; 43 | 44 | if (beatDetected) { 45 | ++beatsDetectedNum; 46 | if (beatsDetectedNum == CALCULATE_EVERY_N_BEATS) { 47 | float acSqRatio = 100.0 * log(redACValueSqSum/samplesRecorded) / log(irACValueSqSum/samplesRecorded); 48 | uint8_t index = 0; 49 | 50 | if (acSqRatio > 66) { 51 | index = (uint8_t)acSqRatio - 66; 52 | } else if (acSqRatio > 50) { 53 | index = (uint8_t)acSqRatio - 50; 54 | } 55 | reset(); 56 | 57 | spO2 = spO2LUT[index]; 58 | } 59 | } 60 | } 61 | 62 | void SpO2Calculator::reset() 63 | { 64 | samplesRecorded = 0; 65 | redACValueSqSum = 0; 66 | irACValueSqSum = 0; 67 | beatsDetectedNum = 0; 68 | spO2 = 0; 69 | } 70 | 71 | uint8_t SpO2Calculator::getSpO2() 72 | { 73 | return spO2; 74 | } 75 | -------------------------------------------------------------------------------- /src/MAX30100_SpO2Calculator.h: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino-MAX30100 oximetry / heart rate integrated sensor library 3 | Copyright (C) 2016 OXullo Intersecans 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef MAX30100_SPO2CALCULATOR_H 20 | #define MAX30100_SPO2CALCULATOR_H 21 | 22 | #include 23 | 24 | #define CALCULATE_EVERY_N_BEATS 3 25 | 26 | class SpO2Calculator { 27 | public: 28 | SpO2Calculator(); 29 | 30 | void update(float irACValue, float redACValue, bool beatDetected); 31 | void reset(); 32 | uint8_t getSpO2(); 33 | 34 | private: 35 | static const uint8_t spO2LUT[43]; 36 | 37 | float irACValueSqSum; 38 | float redACValueSqSum; 39 | uint8_t beatsDetectedNum; 40 | uint32_t samplesRecorded; 41 | uint8_t spO2; 42 | }; 43 | 44 | #endif 45 | --------------------------------------------------------------------------------