├── LICENSE ├── calvec ├── mgraph ├── mkgraph ├── monit ├── monit2 ├── noisemon ├── dayboxer ├── nmonit ├── noisegraph ├── noisemon.grc └── readme.md ├── parselog ├── readme.md ├── specmon-v1.md ├── specmon.grc ├── specmon2.grc ├── specmon2_gui.grc ├── specmon2_replay.grc ├── specmon_cli.grc ├── specreceive.grc ├── testspec └── weekgraph /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /calvec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Description: Calculate a calibration-vector for specmon2 4 | # 5 | # Author: Bart Somers PE1RIK 6 | # 7 | 8 | import argparse 9 | import array #used for fromfile 10 | import numpy as np 11 | 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument('-i', '--infile', type=str, help='Filename with vectors', required=False) 14 | parser.add_argument('-o', '--outfile', type=str, help='Filename where to put output', required=True) 15 | parser.add_argument('-c', '--constant', type=float, help='Constant to use for calculation', required=True) 16 | parser.add_argument('-l', '--length', type=int, help='Vector-length to parse', required=True) 17 | args = parser.parse_args() 18 | 19 | constant_array = [args.constant] * args.length 20 | readlist = array.array('f') 21 | 22 | # Name: DerdeMethode 23 | # Desc: Create a calibration-vector, based on the inputvector 24 | # Input: readlist, outputfile, contstant 25 | # Output: Calibration vector in outputfile 26 | # Return: - 27 | def DerdeMethode(readlist,outputfile, constant): 28 | testout = array.array('f') 29 | for i in range(len(readlist)): 30 | res = constant - readlist[i] 31 | testout.append(float(res)) 32 | 33 | #print (testout) 34 | fout = open(outputfile,'wb') 35 | testout.tofile(fout) 36 | fout.close() 37 | 38 | if args.infile: 39 | # Input file is defined. Create a calibration outputfile 40 | 41 | f=open(args.infile,"rb") 42 | 43 | # Skip first few lines 44 | for i in range(20): 45 | readlist.fromfile(f, args.length) 46 | del readlist[:] 47 | 48 | ## Now read the vector to use 49 | #readlist.fromfile(f, args.length) 50 | #f.close() 51 | 52 | # 210927 Test for more vectors 53 | # Base is 5 vectors per second. 54 | # 20 vectors = 4 seconds 55 | # 300 vectors = 1 minute 56 | vecavg = 20 57 | e = np.zeros(args.length) 58 | for i in range(vecavg): 59 | readlist.fromfile(f, args.length) 60 | #print ("len readlist: ", len(readlist), " len e: ", len(e)) 61 | e = np.add(e,readlist) 62 | # Now clear the list from file. 63 | del readlist[:] 64 | 65 | # Divide by number of vectors 66 | readlist = np.divide(e,vecavg) 67 | f.close() 68 | 69 | # Write the vector to file 70 | DerdeMethode(readlist, args.outfile, args.constant) 71 | else: 72 | # Inputfile is not defined. Create a vector with only the constant value 73 | constant_array = array.array('f', [args.constant] * args.length) 74 | fout = open(args.outfile,'wb') 75 | constant_array.tofile(fout) 76 | fout.close() 77 | 78 | exit(0) 79 | 80 | -------------------------------------------------------------------------------- /mgraph: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Description: Wrapper to create daily graphs from parsed logfile 4 | # 5 | # Author: Bart Somers PE1RIK 6 | # 7 | 8 | # Select the gnuplot-pallet to use. Suggestion: bentcoolwarm.pal 9 | PALLET=/mnt/space/bart/Download/gnuplot-palettes/bentcoolwarm.pal 10 | 11 | if [ ! -f ${PALLET} ]; 12 | then 13 | echo "GNUPLOT Pallet ${PALLET} not found" 14 | exit 1 15 | fi 16 | 17 | if [ -z $1 ]; 18 | then 19 | echo "Usage: $0 " 20 | exit 1 21 | else 22 | 23 | OUTFILE=${1} 24 | fi 25 | 26 | #OUTFILE=${OUTFILE}-test 27 | 28 | gnuplot <<- EOF 29 | set terminal png size 1280,768 30 | set output '${OUTFILE}-month-percent.png' 31 | #set xrange [0:23] 32 | set xlabel "Day" 33 | set ylabel "Hour" 34 | set yrange [0:23] 35 | set cblabel "Percentage of usage" 36 | unset key 37 | load '${PALLET}' 38 | plot "${OUTFILE}" using 12:2:6 with image pixels 39 | 40 | 41 | set terminal png size 1280,768 42 | set output '${OUTFILE}-month-opening.png' 43 | #set xrange [0:23] 44 | set xlabel "Day" 45 | set ylabel "Hour" 46 | set yrange [0:23] 47 | set cblabel "Number of openings" 48 | unset key 49 | load '${PALLET}' 50 | plot "${OUTFILE}" using 12:2:10 with image pixels 51 | 52 | 53 | set terminal png size 1280,768 54 | set output '${OUTFILE}-month-avgopen.png' 55 | #set xrange [0:23] 56 | set xlabel "Day" 57 | set ylabel "Hour" 58 | set yrange [0:23] 59 | set cblabel "Avg open time (s)" 60 | unset key 61 | load '${PALLET}' 62 | plot "${OUTFILE}" using 12:2:14 with image pixels 63 | 64 | 65 | set terminal png size 1280,768 66 | set output '${OUTFILE}-month-maxopen.png' 67 | #set xrange [0:23] 68 | set xlabel "Day" 69 | set ylabel "Hour" 70 | set yrange [0:23] 71 | set cblabel "Max open value" 72 | unset key 73 | load '${PALLET}' 74 | plot "${OUTFILE}" using 12:2:16 with image pixels 75 | 76 | EOF 77 | -------------------------------------------------------------------------------- /mkgraph: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Description: Wrapper to create daily graphs from parsed logfile 4 | # 5 | # Author: Bart Somers PE1RIK 6 | # 7 | 8 | if [ -z $1 ]; 9 | then 10 | echo "Usage: $0 " 11 | exit 1 12 | else 13 | 14 | BESTAND=${1} 15 | fi 16 | 17 | #OUTBESTAND=${BESTAND}-test 18 | OUTBESTAND=${BESTAND} 19 | 20 | gnuplot <<- EOF 21 | set terminal pngcairo size 1024,768 22 | set output '${OUTBESTAND}-percent.png' 23 | set style fill solid 0.5 24 | set style data histograms 25 | set yrange [0:100] 26 | set xrange [0:24] 27 | set xlabel "Hours" 28 | set ylabel "Percent" 29 | plot "${BESTAND}" using 6 linecolor rgb '#0072bd' 30 | #plot "$BESTAND" using 2:6 linecolor rgb '#0072bd' 31 | 32 | set output '${OUTBESTAND}-opening.png' 33 | set style fill solid 0.5 34 | set style data histograms 35 | unset yrange 36 | set xrange [0:24] 37 | set xlabel "Hours" 38 | set ylabel "Number of openings" 39 | plot "${BESTAND}" using 10 linecolor rgb '#4dbeee' 40 | 41 | set output '${OUTBESTAND}-avgopen.png' 42 | set style fill solid 0.5 43 | set style data histograms 44 | unset yrange 45 | set xrange [0:24] 46 | set xlabel "Hours" 47 | set ylabel "Avg open time (s)" 48 | plot "${BESTAND}" using 14 linecolor rgb '#77ac30' 49 | 50 | set output '${OUTBESTAND}-maxopen.png' 51 | set style fill solid 0.5 52 | set style data histograms 53 | unset yrange 54 | set xrange [0:24] 55 | set xlabel "Hours" 56 | set ylabel "Max open value" 57 | plot "${BESTAND}" using 16 linecolor rgb '#fde725' 58 | EOF 59 | 60 | exit 0 61 | -------------------------------------------------------------------------------- /monit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Put to 1 to make this run 4 | ENABLED=1 5 | 6 | THRESHOLD=0.13 7 | GAIN=30 8 | FREQ=446.1e6 9 | RUNTIME=3590 10 | DECIM=10 11 | SAMPRATE=2e6 12 | 13 | # Use the correct tool to run 14 | SPECMON=/home/pi/specmon/specmon_cli.py 15 | #SPECMON=/home/pi/specmon/specmon_cli_pluto.py 16 | 17 | LOGDIR=/tmp 18 | 19 | if [ $ENABLED == 1 ]; 20 | then 21 | if [ ! -d $LOGDIR ]; 22 | then 23 | mkdir -p $LOGDIR ; 24 | fi 25 | 26 | TIMESTAMP=`date +%y%m%d-%H%M` 27 | 28 | 29 | # Specmon with head-block. quits after a defined period of time. (-R) 30 | stdbuf -oL $SPECMON -T $THRESHOLD -g $GAIN -f $FREQ -s $SAMPRATE -D $DECIM -R $RUNTIME > $LOGDIR/specmon2-$TIMESTAMP.csv 2>> $LOGDIR/specmon.debug 31 | 32 | # The next lines are for temperature and runtime debugging, mainly on a Raspberry Pi 33 | # TEMPLOG=/tmp/specmon2-`date +%y%m%d`.templog 34 | # date >> $TEMPLOG 35 | # Next line only for Raspberry Pi 36 | # /opt/vc/bin/vcgencmd measure_temp >> $TEMPLOG 37 | 38 | fi 39 | -------------------------------------------------------------------------------- /monit2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Description: 4 | # Wrapper for specmon2 to run from cron 5 | # Auto clean old recordings from /tmp 6 | # 7 | # Author: Bart Somers PE1RIK 8 | # 9 | 10 | # Put to 1 to make this run 11 | ENABLED=1 12 | 13 | # Put to 1 to automatic clean old recordings in /tmp 14 | # Files older than 2 days are removed 15 | AUTOCLEAN=1 16 | 17 | THRESHOLD=10.0 18 | GAIN=40 19 | FREQ=145e6 20 | RUNTIME=3580 21 | DEVICE="rtl=0" 22 | SAMPRATE=2e6 23 | CALVEC=/home/bart/grc/calvec-145M-G40-2048.0.vec 24 | FFTSIZE=2048 25 | 26 | # Use the correct tool to run 27 | SPECMON=/home/bart/grc/specmon2.py 28 | 29 | # Define the logdir 30 | LOGDIR=/home/bart/log/145 31 | 32 | # Start monitoring if enabled. 33 | if [ $ENABLED == 1 ]; 34 | then 35 | if [ ! -d $LOGDIR ]; 36 | then 37 | mkdir -p $LOGDIR ; 38 | fi 39 | 40 | TIMESTAMP=`date +%y%m%d-%H%M` 41 | echo -e "\nLog started at: ${TIMESTAMP}\n" >> $LOGDIR/specmon2.debug 42 | 43 | 44 | # Specmon with head-block. quits after a defined period of time. (-R) 45 | stdbuf -oL $SPECMON -d $DEVICE -c $CALVEC -T $THRESHOLD -g $GAIN -f $FREQ -s $SAMPRATE -R $RUNTIME -F $FFTSIZE -O $LOGDIR/specmon2-$TIMESTAMP.csv >> $LOGDIR/specmon2.debug 2>&1 46 | 47 | # The next lines are for temperature and runtime debugging, mainly on a Raspberry Pi 48 | # TEMPLOG=/tmp/specmon2-`date +%y%m%d`.templog 49 | # date >> $TEMPLOG 50 | # Next line only for Raspberry Pi 51 | # /opt/vc/bin/vcgencmd measure_temp >> $TEMPLOG 52 | 53 | fi 54 | 55 | # Check to see if autocleaning is enabled. 56 | # Defaults to 2 days old logfiles. 57 | if [ $AUTOCLEAN == 1 ]; 58 | then 59 | cleandate=$(date --date="2 days ago" +%y%m%d) 60 | rm -f /tmp/${cleandate}*pvector 61 | fi 62 | 63 | exit 0 64 | -------------------------------------------------------------------------------- /noisemon/dayboxer: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # 220703 Test boxplot per day 4 | # 5 | # 6 | 7 | OUTDIR="tst" 8 | 9 | if [ ! -d ${OUTDIR} ]; then 10 | mkdir ${OUTDIR} 11 | fi 12 | 13 | if [ -z $1 ] ; then 14 | YESTERDAY=$(date --date=yesterday +%y%m%d) 15 | else 16 | YESTERDAY=$1 17 | echo "Processing day ${YESTERDAY}" 18 | fi 19 | 20 | 21 | # Step 1: Create single value files 22 | for i in noisemon-${YESTERDAY}-{00..23}00.csv; 23 | do 24 | cat $i | cut -d "," -f 3 > ${OUTDIR}/$i 25 | done 26 | 27 | # Step 2: concatenate the files to a single csv 28 | paste -d "," ${OUTDIR}/noisemon-${YESTERDAY}*csv > ${OUTDIR}/${YESTERDAY}.csv 29 | 30 | # Step 3: create the boxplot 31 | 32 | gnuplot <<- EOF 33 | set terminal png size 1280,768 34 | set output '${OUTDIR}/${YESTERDAY}.png' 35 | set datafile separator "," 36 | set style boxplot nooutliers 37 | set style data boxplot 38 | #set boxwidth 0.3 39 | set yrange [-4:0] 40 | plot for [i=1:24] '${OUTDIR}/${YESTERDAY}.csv' using (i):i notitle 41 | 42 | 43 | EOF 44 | 45 | rm ${OUTDIR}/noisemon-${YESTERDAY}*csv 46 | 47 | exit 0 48 | -------------------------------------------------------------------------------- /noisemon/nmonit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Description: 4 | # Wrapper for specmon2 to run from cron 5 | # Auto clean old recordings from /tmp 6 | # 7 | # Author: Bart Somers PE1RIK 8 | # 9 | # ./noisemon.py -f 48e6 -s 2.5e6 -g 12 -F 4096 -c calvec-4096-0.vec -R 120 -d airspy=0 -O /tmp/logfile-dummy-4096-g12.csv 10 | 11 | # Put to 1 to make this run 12 | ENABLED=1 13 | 14 | # Put to 1 to automatic clean old recordings in /tmp 15 | # Files older than 2 days are removed 16 | AUTOCLEAN=1 17 | 18 | GAIN=40 19 | FREQ=145e6 20 | RUNTIME=3580 21 | DEVICE="airspy=0" 22 | SAMPRATE=2e6 23 | #CALVEC=/home/user/noisemon/220911-143M-G40-S2e6-4096-0.calvec 24 | CALVEC=/home/user/noisemon/221014-145M-G40-S2e6-4096-0.calvec 25 | FFTSIZE=4096 26 | SCNLIMIT=3 27 | 28 | # Use the correct tool to run 29 | NOISEMON=/home/user/noisemon/noisemon.py 30 | 31 | # Define the logdir 32 | LOGDIR=/home/user/log/145 33 | 34 | # Start monitoring if enabled. 35 | if [ ${ENABLED} == 1 ]; 36 | then 37 | if [ ! -d ${LOGDIR} ]; 38 | then 39 | mkdir -p ${LOGDIR} ; 40 | fi 41 | 42 | TIMESTAMP=`date +%y%m%d-%H%M` 43 | echo -e "\nLog started at: ${TIMESTAMP}\n" >> ${LOGDIR}/noisemon.debug 44 | 45 | # Run noisemon with the selected parameters 46 | ${NOISEMON} -f ${FREQ} -s ${SAMPRATE} -F ${FFTSIZE} -g ${GAIN} -c ${CALVEC} -R ${RUNTIME} -d ${DEVICE} -S ${SCNLIMIT} -O ${LOGDIR}/noisemon-${TIMESTAMP}.csv >> ${LOGDIR}/noisemon.debug 2>&1 47 | 48 | # The next lines are for temperature and runtime debugging, mainly on a Raspberry Pi 49 | # TEMPLOG=/tmp/specmon2-`date +%y%m%d`.templog 50 | # date >> $TEMPLOG 51 | # Next line only for Raspberry Pi 52 | # /opt/vc/bin/vcgencmd measure_temp >> $TEMPLOG 53 | 54 | fi 55 | 56 | # Check to see if autocleaning is enabled. 57 | # Defaults to 2 days old logfiles. 58 | if [ $AUTOCLEAN == 1 ]; 59 | then 60 | # 2 days 61 | #find /tmp/ -maxdepth 1 -name "*pvector" -mmin +$((2*1440)) -delete 62 | # 1 day 63 | find /tmp/ -maxdepth 1 -name "*pvector" -mmin +1440 -delete 64 | fi 65 | 66 | exit 0 67 | -------------------------------------------------------------------------------- /noisemon/noisegraph: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Description: Wrapper to create daily graphs from parsed logfile 4 | # 5 | # Author: Bart Somers PE1RIK 6 | # 7 | 8 | if [ -z $1 ]; 9 | then 10 | echo "Usage: $0 " 11 | exit 1 12 | else 13 | 14 | BESTAND=${1} 15 | fi 16 | 17 | 18 | #OUTBESTAND=${BESTAND}-test 19 | OUTBESTAND=${BESTAND} 20 | 21 | gnuplot <<- EOF 22 | set datafile separator "," 23 | set terminal pngcairo size 1024,768 24 | set output '${OUTBESTAND}-noise.png' 25 | set xlabel "Minutes" 26 | set ylabel "Noise (relative dB) 27 | set xrange [0:60] 28 | plot "${BESTAND}" using (\$4/300):3 skip 3 title "Noise", "${BESTAND}" using (\$4/300):10 skip 3 title "RMS" 29 | 30 | set datafile separator "," 31 | set terminal pngcairo size 1024,768 32 | set output '${OUTBESTAND}-std.png' 33 | set xlabel "Minutes" 34 | set ylabel "STDev noise" 35 | set xrange [0:60] 36 | plot "${BESTAND}" using (\$4/300):8 skip 3 notitle 37 | 38 | set datafile separator "," 39 | set terminal pngcairo size 1024,768 40 | set output '${OUTBESTAND}-diff.png' 41 | set xlabel "Minutes" 42 | set ylabel "Diff Median and Mean" 43 | set xrange [0:60] 44 | #plot "${BESTAND}" using (\$4/300):(\$3-\$7) skip 3 notitle 45 | plot "${BESTAND}" using (\$4/300):12 skip 3 notitle 46 | 47 | set datafile separator "," 48 | set terminal pngcairo size 1024,768 49 | set output '${OUTBESTAND}-skew.png' 50 | set xlabel "Minutes" 51 | set ylabel "Skewness" 52 | set xrange [0:60] 53 | plot "${BESTAND}" using (\$4/300):9 skip 3 notitle 54 | 55 | set datafile separator "," 56 | set terminal pngcairo size 1024,768 57 | set output '${OUTBESTAND}-use-scn.png' 58 | set xlabel "Minutes" 59 | set ylabel "Usage and SCN count" 60 | set xrange [0:60] 61 | plot "${BESTAND}" using (\$4/300):5 skip 3 title "SCN count", "${BESTAND}" using (\$4/300):6 skip 3 title "Normal Usage count" 62 | 63 | set datafile separator "," 64 | set terminal pngcairo size 2048,768 65 | set output '${OUTBESTAND}-combined.png' 66 | set xlabel "Minutes" 67 | set ylabel "combined values" 68 | set xrange [0:60] 69 | plot "${BESTAND}" using (\$4/300):3 skip 3 title "Noise", \ 70 | "${BESTAND}" using (\$4/300):8 skip 3 title "STDev", \ 71 | "${BESTAND}" using (\$4/300):12 skip 3 title "Diff Mean Median", \ 72 | "${BESTAND}" using (\$4/300):9 skip 3 title "Skewness", \ 73 | #"${BESTAND}" using (\$4/300):5 skip 3 title "SCN count", \ 74 | #"${BESTAND}" using (\$4/300):6 skip 3 title "Normal Usage count" 75 | 76 | EOF 77 | 78 | exit 0 79 | -------------------------------------------------------------------------------- /noisemon/noisemon.grc: -------------------------------------------------------------------------------- 1 | options: 2 | parameters: 3 | author: PE1RIK 4 | category: '[GRC Hier Blocks]' 5 | cmake_opt: '' 6 | comment: '' 7 | copyright: '' 8 | description: '' 9 | gen_cmake: 'On' 10 | gen_linking: dynamic 11 | generate_options: no_gui 12 | hier_block_src_path: '.:' 13 | id: noisemon 14 | max_nouts: '0' 15 | output_language: python 16 | placement: (0,0) 17 | qt_qss_theme: '' 18 | realtime_scheduling: '' 19 | run: 'True' 20 | run_command: '{python} -u {filename}' 21 | run_options: run 22 | sizing_mode: fixed 23 | thread_safe_setters: '' 24 | title: '' 25 | window_size: '' 26 | states: 27 | bus_sink: false 28 | bus_source: false 29 | bus_structure: null 30 | coordinate: [8, 8] 31 | rotation: 0 32 | state: enabled 33 | 34 | blocks: 35 | - name: fhandler 36 | id: variable 37 | parameters: 38 | comment: '' 39 | value: '0' 40 | states: 41 | bus_sink: false 42 | bus_source: false 43 | bus_structure: null 44 | coordinate: [1232, 164.0] 45 | rotation: 0 46 | state: disabled 47 | - name: intcount 48 | id: variable 49 | parameters: 50 | comment: 'Integration count. 51 | 52 | Also used for normalisation 53 | 54 | 55 | vector_rate is vectors per second 56 | 57 | 58 | intcount = samp_rate/(fftsize * vector_rate) 59 | 60 | 61 | Bij vector_rate = 5 (200ms): 62 | 63 | 64 | intcount = samp_rate/(fftsize * 5)' 65 | value: int(samp_rate/(fftsize * 5)) 66 | states: 67 | bus_sink: false 68 | bus_source: false 69 | bus_structure: null 70 | coordinate: [880, 316.0] 71 | rotation: 0 72 | state: enabled 73 | - name: SCNLimit 74 | id: parameter 75 | parameters: 76 | alias: '' 77 | comment: '' 78 | hide: none 79 | label: SCN-Limit 80 | short_id: S 81 | type: intx 82 | value: '3' 83 | states: 84 | bus_sink: false 85 | bus_source: false 86 | bus_structure: null 87 | coordinate: [1008, 32.0] 88 | rotation: 0 89 | state: true 90 | - name: bbgain 91 | id: parameter 92 | parameters: 93 | alias: '' 94 | comment: '' 95 | hide: none 96 | label: BB-Gain 97 | short_id: b 98 | type: intx 99 | value: '30' 100 | states: 101 | bus_sink: false 102 | bus_source: false 103 | bus_structure: null 104 | coordinate: [632, 32] 105 | rotation: 0 106 | state: enabled 107 | - name: blocks_add_xx_0 108 | id: blocks_add_xx 109 | parameters: 110 | affinity: '' 111 | alias: '' 112 | comment: '' 113 | maxoutbuf: '0' 114 | minoutbuf: '0' 115 | num_inputs: '2' 116 | type: float 117 | vlen: fftsize 118 | states: 119 | bus_sink: false 120 | bus_source: false 121 | bus_structure: null 122 | coordinate: [304, 536.0] 123 | rotation: 180 124 | state: enabled 125 | - name: blocks_complex_to_mag_squared_0 126 | id: blocks_complex_to_mag_squared 127 | parameters: 128 | affinity: '' 129 | alias: '' 130 | comment: '' 131 | maxoutbuf: '0' 132 | minoutbuf: '0' 133 | vlen: fftsize 134 | states: 135 | bus_sink: false 136 | bus_source: false 137 | bus_structure: null 138 | coordinate: [1152, 544.0] 139 | rotation: 180 140 | state: enabled 141 | - name: blocks_file_sink_0 142 | id: blocks_file_sink 143 | parameters: 144 | affinity: '' 145 | alias: '' 146 | append: 'False' 147 | comment: 'Debug option to save vector before 148 | 149 | calibration and specmon2 logics' 150 | file: '"/tmp/" + time.strftime("%y%m%d-%H%M") + "-" + str(int(freq)) + "-" + str(int(samp_rate)) 151 | + "-" + str(fftsize) + ".pvector"' 152 | type: float 153 | unbuffered: 'False' 154 | vlen: fftsize 155 | states: 156 | bus_sink: false 157 | bus_source: false 158 | bus_structure: null 159 | coordinate: [272, 728.0] 160 | rotation: 180 161 | state: enabled 162 | - name: blocks_file_source_0 163 | id: blocks_file_source 164 | parameters: 165 | affinity: '' 166 | alias: '' 167 | begin_tag: pmt.PMT_NIL 168 | comment: '' 169 | file: calibvec 170 | length: '0' 171 | maxoutbuf: '0' 172 | minoutbuf: '0' 173 | offset: '0' 174 | repeat: 'True' 175 | type: float 176 | vlen: fftsize 177 | states: 178 | bus_sink: false 179 | bus_source: false 180 | bus_structure: null 181 | coordinate: [552, 696.0] 182 | rotation: 180 183 | state: enabled 184 | - name: blocks_head_0 185 | id: blocks_head 186 | parameters: 187 | affinity: '' 188 | alias: '' 189 | comment: '' 190 | maxoutbuf: '0' 191 | minoutbuf: '0' 192 | num_items: int(runtime*samp_rate) 193 | type: complex 194 | vlen: '1' 195 | states: 196 | bus_sink: false 197 | bus_source: false 198 | bus_structure: null 199 | coordinate: [320, 232.0] 200 | rotation: 0 201 | state: enabled 202 | - name: blocks_integrate_xx_0 203 | id: blocks_integrate_xx 204 | parameters: 205 | affinity: '' 206 | alias: '' 207 | comment: '' 208 | decim: intcount 209 | maxoutbuf: '0' 210 | minoutbuf: '0' 211 | type: float 212 | vlen: fftsize 213 | states: 214 | bus_sink: false 215 | bus_source: false 216 | bus_structure: null 217 | coordinate: [960, 536.0] 218 | rotation: 180 219 | state: enabled 220 | - name: blocks_moving_average_xx_0 221 | id: blocks_moving_average_xx 222 | parameters: 223 | affinity: '' 224 | alias: '' 225 | comment: '' 226 | length: '500' 227 | max_iter: '4000' 228 | maxoutbuf: '0' 229 | minoutbuf: '0' 230 | scale: 1.0/500 231 | type: complex 232 | vlen: '1' 233 | states: 234 | bus_sink: false 235 | bus_source: false 236 | bus_structure: null 237 | coordinate: [472, 288.0] 238 | rotation: 0 239 | state: enabled 240 | - name: blocks_multiply_const_vxx_0 241 | id: blocks_multiply_const_vxx 242 | parameters: 243 | affinity: '' 244 | alias: '' 245 | comment: Normalize integrated vectors 246 | const: '[1.0/intcount]*fftsize' 247 | maxoutbuf: '0' 248 | minoutbuf: '0' 249 | type: float 250 | vlen: fftsize 251 | states: 252 | bus_sink: false 253 | bus_source: false 254 | bus_structure: null 255 | coordinate: [736, 536.0] 256 | rotation: 180 257 | state: enabled 258 | - name: blocks_nlog10_ff_0 259 | id: blocks_nlog10_ff 260 | parameters: 261 | affinity: '' 262 | alias: '' 263 | comment: '' 264 | k: '0' 265 | maxoutbuf: '0' 266 | minoutbuf: '0' 267 | n: '10' 268 | vlen: fftsize 269 | states: 270 | bus_sink: false 271 | bus_source: false 272 | bus_structure: null 273 | coordinate: [544, 528.0] 274 | rotation: 180 275 | state: enabled 276 | - name: blocks_stream_to_vector_0 277 | id: blocks_stream_to_vector 278 | parameters: 279 | affinity: '' 280 | alias: '' 281 | comment: '' 282 | maxoutbuf: '0' 283 | minoutbuf: '0' 284 | num_items: fftsize 285 | type: complex 286 | vlen: '1' 287 | states: 288 | bus_sink: false 289 | bus_source: false 290 | bus_structure: null 291 | coordinate: [832, 248] 292 | rotation: 0 293 | state: enabled 294 | - name: blocks_sub_xx_0 295 | id: blocks_sub_xx 296 | parameters: 297 | affinity: '' 298 | alias: '' 299 | comment: '' 300 | maxoutbuf: '0' 301 | minoutbuf: '0' 302 | num_inputs: '2' 303 | type: complex 304 | vlen: '1' 305 | states: 306 | bus_sink: false 307 | bus_source: false 308 | bus_structure: null 309 | coordinate: [656, 224] 310 | rotation: 0 311 | state: enabled 312 | - name: calibvec 313 | id: parameter 314 | parameters: 315 | alias: '' 316 | comment: '' 317 | hide: none 318 | label: Calibration Vector 319 | short_id: c 320 | type: str 321 | value: '0' 322 | states: 323 | bus_sink: false 324 | bus_source: false 325 | bus_structure: null 326 | coordinate: [760, 656.0] 327 | rotation: 0 328 | state: enabled 329 | - name: deviceid 330 | id: parameter 331 | parameters: 332 | alias: '' 333 | comment: '' 334 | hide: none 335 | label: Device ID 336 | short_id: d 337 | type: str 338 | value: '"rtl=00000201"' 339 | states: 340 | bus_sink: false 341 | bus_source: false 342 | bus_structure: null 343 | coordinate: [240, 32] 344 | rotation: 0 345 | state: enabled 346 | - name: fft_vxx_0 347 | id: fft_vxx 348 | parameters: 349 | affinity: '' 350 | alias: '' 351 | comment: '' 352 | fft_size: fftsize 353 | forward: 'True' 354 | maxoutbuf: '0' 355 | minoutbuf: '0' 356 | nthreads: '1' 357 | shift: 'True' 358 | type: complex 359 | window: window.blackmanharris(fftsize) 360 | states: 361 | bus_sink: false 362 | bus_source: false 363 | bus_structure: null 364 | coordinate: [1024, 216] 365 | rotation: 0 366 | state: enabled 367 | - name: fftsize 368 | id: parameter 369 | parameters: 370 | alias: '' 371 | comment: '' 372 | hide: none 373 | label: FFT size 374 | short_id: F 375 | type: intx 376 | value: '1024' 377 | states: 378 | bus_sink: false 379 | bus_source: false 380 | bus_structure: null 381 | coordinate: [944, 656.0] 382 | rotation: 0 383 | state: enabled 384 | - name: freq 385 | id: parameter 386 | parameters: 387 | alias: '' 388 | comment: '' 389 | hide: none 390 | label: Frequency 391 | short_id: f 392 | type: eng_float 393 | value: 145e6 394 | states: 395 | bus_sink: false 396 | bus_source: false 397 | bus_structure: null 398 | coordinate: [392, 32] 399 | rotation: 0 400 | state: enabled 401 | - name: import_0 402 | id: import 403 | parameters: 404 | alias: '' 405 | comment: "Required when not \nusing osmocom source" 406 | imports: import time 407 | states: 408 | bus_sink: false 409 | bus_source: false 410 | bus_structure: null 411 | coordinate: [16, 776.0] 412 | rotation: 0 413 | state: enabled 414 | - name: noisemon_block 415 | id: epy_block 416 | parameters: 417 | SCNLimit: SCNLimit 418 | _source_code: "\"\"\"\nEmbedded Python Blocks:\n\nEach time this file is saved,\ 419 | \ GRC will instantiate the first class it finds\nto get ports and parameters\ 420 | \ of your block. The arguments to __init__ will\nbe the parameters. All of\ 421 | \ them are required to have default values!\n\"\"\"\n\nimport numpy as np\n\ 422 | from gnuradio import gr\nimport time\nfrom scipy.stats import skew\n\n\nclass\ 423 | \ blk(gr.sync_block): # other base classes are basic_block, decim_block, interp_block\n\ 424 | \ \"\"\"Noisemon data analysis block. \n This block is the new version\ 425 | \ to measure noise levels.\n \n Detect SCN and background noise. No Impulse\ 426 | \ Noise yet.\n \"\"\"\n\n\t# Don't use \"logfile\" as varname as it's reserved\ 427 | \ in GRC\n #def __init__(self, fftsize=1024, start_state=0, threshold=1.0,\ 428 | \ verbose=0, reportfile=\"/tmp/logfile.csv\"): # only default arguments here\n\ 429 | \ def __init__(self, fftsize=1024, reportfile=\"/tmp/logfile.csv\", threshold=8.0,\ 430 | \ SCNLimit=1): # only default arguments here\n \"\"\"arguments to this\ 431 | \ function show up as parameters in GRC\"\"\"\n self.fftsize = fftsize\n\ 432 | \ self.reportfile = reportfile\n self.threshold = threshold\n\ 433 | \ self.SCNLimit = SCNLimit\n gr.sync_block.__init__(\n \ 434 | \ self,\n name='Noisemon', # will show up in GRC\n \ 435 | \ in_sig=[(np.float32,fftsize)],\n out_sig=None\n )\n \ 436 | \ # Print startline\n self.outfile = open(reportfile, \"a\")\n\ 437 | \ print (\"Start,%.2f,Hour,%s,Veclen,%i,Threshold,%.2f,SCNLimit,%i\"\ 438 | \ % ( time.time(), str(time.strftime(\"%H\")), self.fftsize, self.threshold,\ 439 | \ self.SCNLimit), file=self.outfile, flush=True )\n \n # Print\ 440 | \ header\n print (\"N,time,lowlimit,veccount,scncount,nusage,vecmean,vecstd,vecskew,rms,inoise,diff\"\ 441 | , file=self.outfile, flush=True)\n # Counter for the number of vectors\n\ 442 | \ self.veccount = 0\n # Buffer for the old STDev\n # Start\ 443 | \ with high value to prevent first vector as false positive\n # 230514\ 444 | \ try an array\n self.oldstdev = []\n \n \n def work(self,\ 445 | \ input_items, output_items):\n \n for j in range(len(input_items[0])):\n\ 446 | \ if len(input_items[0][j]) == self.fftsize:\n \ 447 | \ # Correct length\n \n \ 448 | \ # print (\"New Vector\")\n \n \ 449 | \ speclist = np.array(input_items[0][j])\n \n \ 450 | \ # 220917 trunk the list to the usable value for the Airspy\ 451 | \ in 2.5MSps\n # use 0.6, so extract 0.2 on both sides.\n\ 452 | \ # See notes on 220917\n # Use\ 453 | \ 0.5, so extract 0.25 on both sides.\n # See notes on\ 454 | \ 230514\n #trunklist = speclist[(int(self.fftsize*0.25)):(int(self.fftsize-(self.fftsize*0.25)))]\n\ 455 | \ #olist = np.sort(trunklist)\n \ 456 | \ \n olist = np.sort(speclist)\n \ 457 | \ \n # Create a short vector in one place and use\ 458 | \ everywhere\n # Use the first 50% for now. ITU-R SM.1753-2\ 459 | \ suggest other.\n # Delete the first 10 values, as these\ 460 | \ usually hold the DC-spike.\n shortvec = olist[10:(int(len(olist)/2))]\n\ 461 | \ \n lowlimit = np.median(shortvec)\n\ 462 | \ \n # Stats on the short vector\n\ 463 | \ vecmean = np.mean(shortvec)\n \ 464 | \ vecstd = np.std(shortvec)\n \n \ 465 | \ # Try to detect Impulse Noise\n inoise = 0\n \ 466 | \ self.oldstdev.append(vecstd)\n \ 467 | \ stdevavg = sum(self.oldstdev)/len(self.oldstdev)\n \ 468 | \ #if vecstd > (1.25 * self.oldstdev):\n if vecstd\ 469 | \ > (1.25 * stdevavg):\n inoise = 1\n \ 470 | \ \n # Update oldstdev\n \ 471 | \ #self.oldstdev = vecstd\n if len(self.oldstdev)\ 472 | \ > 25:\n del self.oldstdev[0:1]\n \ 473 | \ \n # Calculate skewness\n \ 474 | \ vecskew = skew(shortvec)\n \n \ 475 | \ # Calculate RMS\n b = np.square(shortvec)\n\ 476 | \ vecrms = np.sqrt((np.sum(b)/len(b)))\n\n \ 477 | \ # Now detect SNC (and normal usage)\n \ 478 | \ \n # Create output-vector of lowlimit + threshold\n\ 479 | \ #output_items[0][:] = [lowlimit + self.threshold]*self.fftsize\n\ 480 | \ \n highcount\ 481 | \ = 0\n scncount = 0\n nusage\ 482 | \ = 0\n\n for i in speclist:\n \ 483 | \ if i < (lowlimit + self.threshold):\n #if\ 484 | \ i == 0:\n # Low\n \ 485 | \ #print (\"Value is low: \", i, \" Limit: \", (lowlimit + self.threshold)\ 486 | \ )\n \n # Now\ 487 | \ consider highcounter\n # If highcounter = 0\ 488 | \ nothing before\n # If highcounter = 1 consider\ 489 | \ SCN\n # If highcounter > 1 consider normal\ 490 | \ usage\n \n if\ 491 | \ highcount == 0:\n # Nothing before\n \ 492 | \ #next\n \ 493 | \ pass\n elif highcount <= self.SCNLimit :\n\ 494 | \ # We might have SCN\n \ 495 | \ #print (\"SCN Detected\")\n \ 496 | \ scncount += 1\n elif highcount > self.SCNLimit:\n\ 497 | \ # We might have normal usage\n \ 498 | \ # print (\"Normal Usage detected. highcount: \"\ 499 | , highcount)\n nusage += 1\n \ 500 | \ \n # Reset counter\n \ 501 | \ highcount = 0\n \ 502 | \ \n else:\n # High\n\ 503 | \ #print (\"Value is high: \", i, \" Limit: \"\ 504 | , (lowlimit + self.threshold) )\n \n \ 505 | \ # Increase highcounter \n \ 506 | \ highcount += 1\n \ 507 | \ \n #print (\"Vectors: \", len(speclist), \" SCN:\ 508 | \ \", scncount, \" Normal: \", nusage, \" Low: \", lowlimit, \" Thresh: \",\ 509 | \ self.threshold, \" Mean: \", vecmean, \" STD: \", vecstd)\n \ 510 | \ #print (\"V: %i L: %i S: %i N: %i L: %.2f T: %.2f M: %.2f std: %.2f\"\ 511 | \ % ( len(speclist), self.SCNLimit, scncount, nusage, lowlimit, self.threshold,\ 512 | \ vecmean, vecstd ) ) \n # Without veclen, scnlimit,\ 513 | \ threshold (in header)\n #print (\"S: %i N: %i L: %.2f\ 514 | \ M: %.2f std: %.2f skew: %.2f rms: %.2f\" % ( scncount, nusage, lowlimit, vecmean,\ 515 | \ vecstd, vecskew, vecrms ) ) \n\n \n \ 516 | \ \n # Debug with vector counter\n \ 517 | \ self.veccount+=1\n #print (\"N,%.2f,%.2f,%i\"\ 518 | \ % (time.time(), lowlimit, self.veccount), end=\"\\n\", file=self.outfile,\ 519 | \ flush=True )\n # N,time,lowlimit,scncount, nusage,vecmean,vecstd,veccount\n\ 520 | \ print (\"N,%.2f,%.2f,%i,%i,%i,%.2f,%.2f,%.2f,%.2f,%i,%.2f\"\ 521 | \ % (time.time(), lowlimit, self.veccount, scncount, nusage, vecmean, vecstd,\ 522 | \ vecskew, vecrms, inoise, abs(lowlimit-vecmean)), end=\"\\n\", file=self.outfile,\ 523 | \ flush=True )\n else:\n print (\"Other\ 524 | \ length input: \" + str(len(input_items[0][j])))\n \n return\ 525 | \ len(input_items[0])\n" 526 | affinity: '' 527 | alias: '' 528 | comment: 'Overal moeten de standaardwaarden gelijk zijn, 529 | 530 | in dit geval dus 4096. 531 | 532 | Pas na compilen kan met een parameter de FFTSIZE veranderd 533 | 534 | worden.' 535 | fftsize: fftsize 536 | maxoutbuf: '0' 537 | minoutbuf: '0' 538 | reportfile: outfile 539 | threshold: threshold 540 | states: 541 | _io_cache: ('Noisemon', 'blk', [('fftsize', '1024'), ('reportfile', "'/tmp/logfile.csv'"), 542 | ('threshold', '8.0'), ('SCNLimit', '1')], [('0', 'float', 1024)], [], 'Noisemon 543 | data analysis block. \n This block is the new version to measure noise levels.\n \n Detect 544 | SCN and background noise. No Impulse Noise yet.\n ', ['SCNLimit', 'fftsize', 545 | 'reportfile', 'threshold']) 546 | bus_sink: false 547 | bus_source: false 548 | bus_structure: null 549 | coordinate: [32, 496.0] 550 | rotation: 180 551 | state: enabled 552 | - name: osmosdr_source_0 553 | id: osmosdr_source 554 | parameters: 555 | affinity: '' 556 | alias: '' 557 | ant0: '' 558 | ant1: '' 559 | ant10: '' 560 | ant11: '' 561 | ant12: '' 562 | ant13: '' 563 | ant14: '' 564 | ant15: '' 565 | ant16: '' 566 | ant17: '' 567 | ant18: '' 568 | ant19: '' 569 | ant2: '' 570 | ant20: '' 571 | ant21: '' 572 | ant22: '' 573 | ant23: '' 574 | ant24: '' 575 | ant25: '' 576 | ant26: '' 577 | ant27: '' 578 | ant28: '' 579 | ant29: '' 580 | ant3: '' 581 | ant30: '' 582 | ant31: '' 583 | ant4: '' 584 | ant5: '' 585 | ant6: '' 586 | ant7: '' 587 | ant8: '' 588 | ant9: '' 589 | args: deviceid 590 | bb_gain0: bbgain 591 | bb_gain1: '20' 592 | bb_gain10: '20' 593 | bb_gain11: '20' 594 | bb_gain12: '20' 595 | bb_gain13: '20' 596 | bb_gain14: '20' 597 | bb_gain15: '20' 598 | bb_gain16: '20' 599 | bb_gain17: '20' 600 | bb_gain18: '20' 601 | bb_gain19: '20' 602 | bb_gain2: '20' 603 | bb_gain20: '20' 604 | bb_gain21: '20' 605 | bb_gain22: '20' 606 | bb_gain23: '20' 607 | bb_gain24: '20' 608 | bb_gain25: '20' 609 | bb_gain26: '20' 610 | bb_gain27: '20' 611 | bb_gain28: '20' 612 | bb_gain29: '20' 613 | bb_gain3: '20' 614 | bb_gain30: '20' 615 | bb_gain31: '20' 616 | bb_gain4: '20' 617 | bb_gain5: '20' 618 | bb_gain6: '20' 619 | bb_gain7: '20' 620 | bb_gain8: '20' 621 | bb_gain9: '20' 622 | bw0: '0' 623 | bw1: '0' 624 | bw10: '0' 625 | bw11: '0' 626 | bw12: '0' 627 | bw13: '0' 628 | bw14: '0' 629 | bw15: '0' 630 | bw16: '0' 631 | bw17: '0' 632 | bw18: '0' 633 | bw19: '0' 634 | bw2: '0' 635 | bw20: '0' 636 | bw21: '0' 637 | bw22: '0' 638 | bw23: '0' 639 | bw24: '0' 640 | bw25: '0' 641 | bw26: '0' 642 | bw27: '0' 643 | bw28: '0' 644 | bw29: '0' 645 | bw3: '0' 646 | bw30: '0' 647 | bw31: '0' 648 | bw4: '0' 649 | bw5: '0' 650 | bw6: '0' 651 | bw7: '0' 652 | bw8: '0' 653 | bw9: '0' 654 | clock_source0: '' 655 | clock_source1: '' 656 | clock_source2: '' 657 | clock_source3: '' 658 | clock_source4: '' 659 | clock_source5: '' 660 | clock_source6: '' 661 | clock_source7: '' 662 | comment: '' 663 | corr0: '0' 664 | corr1: '0' 665 | corr10: '0' 666 | corr11: '0' 667 | corr12: '0' 668 | corr13: '0' 669 | corr14: '0' 670 | corr15: '0' 671 | corr16: '0' 672 | corr17: '0' 673 | corr18: '0' 674 | corr19: '0' 675 | corr2: '0' 676 | corr20: '0' 677 | corr21: '0' 678 | corr22: '0' 679 | corr23: '0' 680 | corr24: '0' 681 | corr25: '0' 682 | corr26: '0' 683 | corr27: '0' 684 | corr28: '0' 685 | corr29: '0' 686 | corr3: '0' 687 | corr30: '0' 688 | corr31: '0' 689 | corr4: '0' 690 | corr5: '0' 691 | corr6: '0' 692 | corr7: '0' 693 | corr8: '0' 694 | corr9: '0' 695 | dc_offset_mode0: '2' 696 | dc_offset_mode1: '0' 697 | dc_offset_mode10: '0' 698 | dc_offset_mode11: '0' 699 | dc_offset_mode12: '0' 700 | dc_offset_mode13: '0' 701 | dc_offset_mode14: '0' 702 | dc_offset_mode15: '0' 703 | dc_offset_mode16: '0' 704 | dc_offset_mode17: '0' 705 | dc_offset_mode18: '0' 706 | dc_offset_mode19: '0' 707 | dc_offset_mode2: '0' 708 | dc_offset_mode20: '0' 709 | dc_offset_mode21: '0' 710 | dc_offset_mode22: '0' 711 | dc_offset_mode23: '0' 712 | dc_offset_mode24: '0' 713 | dc_offset_mode25: '0' 714 | dc_offset_mode26: '0' 715 | dc_offset_mode27: '0' 716 | dc_offset_mode28: '0' 717 | dc_offset_mode29: '0' 718 | dc_offset_mode3: '0' 719 | dc_offset_mode30: '0' 720 | dc_offset_mode31: '0' 721 | dc_offset_mode4: '0' 722 | dc_offset_mode5: '0' 723 | dc_offset_mode6: '0' 724 | dc_offset_mode7: '0' 725 | dc_offset_mode8: '0' 726 | dc_offset_mode9: '0' 727 | freq0: freq 728 | freq1: 100e6 729 | freq10: 100e6 730 | freq11: 100e6 731 | freq12: 100e6 732 | freq13: 100e6 733 | freq14: 100e6 734 | freq15: 100e6 735 | freq16: 100e6 736 | freq17: 100e6 737 | freq18: 100e6 738 | freq19: 100e6 739 | freq2: 100e6 740 | freq20: 100e6 741 | freq21: 100e6 742 | freq22: 100e6 743 | freq23: 100e6 744 | freq24: 100e6 745 | freq25: 100e6 746 | freq26: 100e6 747 | freq27: 100e6 748 | freq28: 100e6 749 | freq29: 100e6 750 | freq3: 100e6 751 | freq30: 100e6 752 | freq31: 100e6 753 | freq4: 100e6 754 | freq5: 100e6 755 | freq6: 100e6 756 | freq7: 100e6 757 | freq8: 100e6 758 | freq9: 100e6 759 | gain0: rfgain 760 | gain1: '10' 761 | gain10: '10' 762 | gain11: '10' 763 | gain12: '10' 764 | gain13: '10' 765 | gain14: '10' 766 | gain15: '10' 767 | gain16: '10' 768 | gain17: '10' 769 | gain18: '10' 770 | gain19: '10' 771 | gain2: '10' 772 | gain20: '10' 773 | gain21: '10' 774 | gain22: '10' 775 | gain23: '10' 776 | gain24: '10' 777 | gain25: '10' 778 | gain26: '10' 779 | gain27: '10' 780 | gain28: '10' 781 | gain29: '10' 782 | gain3: '10' 783 | gain30: '10' 784 | gain31: '10' 785 | gain4: '10' 786 | gain5: '10' 787 | gain6: '10' 788 | gain7: '10' 789 | gain8: '10' 790 | gain9: '10' 791 | gain_mode0: 'False' 792 | gain_mode1: 'False' 793 | gain_mode10: 'False' 794 | gain_mode11: 'False' 795 | gain_mode12: 'False' 796 | gain_mode13: 'False' 797 | gain_mode14: 'False' 798 | gain_mode15: 'False' 799 | gain_mode16: 'False' 800 | gain_mode17: 'False' 801 | gain_mode18: 'False' 802 | gain_mode19: 'False' 803 | gain_mode2: 'False' 804 | gain_mode20: 'False' 805 | gain_mode21: 'False' 806 | gain_mode22: 'False' 807 | gain_mode23: 'False' 808 | gain_mode24: 'False' 809 | gain_mode25: 'False' 810 | gain_mode26: 'False' 811 | gain_mode27: 'False' 812 | gain_mode28: 'False' 813 | gain_mode29: 'False' 814 | gain_mode3: 'False' 815 | gain_mode30: 'False' 816 | gain_mode31: 'False' 817 | gain_mode4: 'False' 818 | gain_mode5: 'False' 819 | gain_mode6: 'False' 820 | gain_mode7: 'False' 821 | gain_mode8: 'False' 822 | gain_mode9: 'False' 823 | if_gain0: '20' 824 | if_gain1: '20' 825 | if_gain10: '20' 826 | if_gain11: '20' 827 | if_gain12: '20' 828 | if_gain13: '20' 829 | if_gain14: '20' 830 | if_gain15: '20' 831 | if_gain16: '20' 832 | if_gain17: '20' 833 | if_gain18: '20' 834 | if_gain19: '20' 835 | if_gain2: '20' 836 | if_gain20: '20' 837 | if_gain21: '20' 838 | if_gain22: '20' 839 | if_gain23: '20' 840 | if_gain24: '20' 841 | if_gain25: '20' 842 | if_gain26: '20' 843 | if_gain27: '20' 844 | if_gain28: '20' 845 | if_gain29: '20' 846 | if_gain3: '20' 847 | if_gain30: '20' 848 | if_gain31: '20' 849 | if_gain4: '20' 850 | if_gain5: '20' 851 | if_gain6: '20' 852 | if_gain7: '20' 853 | if_gain8: '20' 854 | if_gain9: '20' 855 | iq_balance_mode0: '0' 856 | iq_balance_mode1: '0' 857 | iq_balance_mode10: '0' 858 | iq_balance_mode11: '0' 859 | iq_balance_mode12: '0' 860 | iq_balance_mode13: '0' 861 | iq_balance_mode14: '0' 862 | iq_balance_mode15: '0' 863 | iq_balance_mode16: '0' 864 | iq_balance_mode17: '0' 865 | iq_balance_mode18: '0' 866 | iq_balance_mode19: '0' 867 | iq_balance_mode2: '0' 868 | iq_balance_mode20: '0' 869 | iq_balance_mode21: '0' 870 | iq_balance_mode22: '0' 871 | iq_balance_mode23: '0' 872 | iq_balance_mode24: '0' 873 | iq_balance_mode25: '0' 874 | iq_balance_mode26: '0' 875 | iq_balance_mode27: '0' 876 | iq_balance_mode28: '0' 877 | iq_balance_mode29: '0' 878 | iq_balance_mode3: '0' 879 | iq_balance_mode30: '0' 880 | iq_balance_mode31: '0' 881 | iq_balance_mode4: '0' 882 | iq_balance_mode5: '0' 883 | iq_balance_mode6: '0' 884 | iq_balance_mode7: '0' 885 | iq_balance_mode8: '0' 886 | iq_balance_mode9: '0' 887 | maxoutbuf: '0' 888 | minoutbuf: '0' 889 | nchan: '1' 890 | num_mboards: '1' 891 | sample_rate: samp_rate 892 | sync: sync 893 | time_source0: '' 894 | time_source1: '' 895 | time_source2: '' 896 | time_source3: '' 897 | time_source4: '' 898 | time_source5: '' 899 | time_source6: '' 900 | time_source7: '' 901 | type: fc32 902 | states: 903 | bus_sink: false 904 | bus_source: false 905 | bus_structure: null 906 | coordinate: [16, 236.0] 907 | rotation: 0 908 | state: enabled 909 | - name: outfile 910 | id: parameter 911 | parameters: 912 | alias: '' 913 | comment: '' 914 | hide: none 915 | label: Output File 916 | short_id: O 917 | type: str 918 | value: '"/tmp/logfile.csv"' 919 | states: 920 | bus_sink: false 921 | bus_source: false 922 | bus_structure: null 923 | coordinate: [1192, 36.0] 924 | rotation: 0 925 | state: true 926 | - name: rfgain 927 | id: parameter 928 | parameters: 929 | alias: '' 930 | comment: '' 931 | hide: none 932 | label: RF-Gain 933 | short_id: g 934 | type: intx 935 | value: '40' 936 | states: 937 | bus_sink: false 938 | bus_source: false 939 | bus_structure: null 940 | coordinate: [520, 32] 941 | rotation: 0 942 | state: enabled 943 | - name: runtime 944 | id: parameter 945 | parameters: 946 | alias: '' 947 | comment: '' 948 | hide: none 949 | label: '' 950 | short_id: R 951 | type: intx 952 | value: '3590' 953 | states: 954 | bus_sink: false 955 | bus_source: false 956 | bus_structure: null 957 | coordinate: [320, 328.0] 958 | rotation: 0 959 | state: enabled 960 | - name: samp_rate 961 | id: parameter 962 | parameters: 963 | alias: '' 964 | comment: '' 965 | hide: none 966 | label: Sample Rate 967 | short_id: s 968 | type: eng_float 969 | value: 2e6 970 | states: 971 | bus_sink: false 972 | bus_source: false 973 | bus_structure: null 974 | coordinate: [872, 32] 975 | rotation: 0 976 | state: enabled 977 | - name: threshold 978 | id: parameter 979 | parameters: 980 | alias: '' 981 | comment: '' 982 | hide: none 983 | label: Threshold 984 | short_id: T 985 | type: eng_float 986 | value: '8.0' 987 | states: 988 | bus_sink: false 989 | bus_source: false 990 | bus_structure: null 991 | coordinate: [752, 32] 992 | rotation: 0 993 | state: enabled 994 | - name: zeromq_pub_sink_0 995 | id: zeromq_pub_sink 996 | parameters: 997 | address: tcp://*:50001 998 | affinity: '' 999 | alias: '' 1000 | comment: '' 1001 | hwm: '-1' 1002 | pass_tags: 'False' 1003 | timeout: '100' 1004 | type: float 1005 | vlen: fftsize 1006 | states: 1007 | bus_sink: false 1008 | bus_source: false 1009 | bus_structure: null 1010 | coordinate: [40, 656.0] 1011 | rotation: 180 1012 | state: true 1013 | 1014 | connections: 1015 | - [blocks_add_xx_0, '0', noisemon_block, '0'] 1016 | - [blocks_add_xx_0, '0', zeromq_pub_sink_0, '0'] 1017 | - [blocks_complex_to_mag_squared_0, '0', blocks_integrate_xx_0, '0'] 1018 | - [blocks_file_source_0, '0', blocks_add_xx_0, '1'] 1019 | - [blocks_head_0, '0', blocks_moving_average_xx_0, '0'] 1020 | - [blocks_head_0, '0', blocks_sub_xx_0, '0'] 1021 | - [blocks_integrate_xx_0, '0', blocks_multiply_const_vxx_0, '0'] 1022 | - [blocks_moving_average_xx_0, '0', blocks_sub_xx_0, '1'] 1023 | - [blocks_multiply_const_vxx_0, '0', blocks_nlog10_ff_0, '0'] 1024 | - [blocks_nlog10_ff_0, '0', blocks_add_xx_0, '0'] 1025 | - [blocks_nlog10_ff_0, '0', blocks_file_sink_0, '0'] 1026 | - [blocks_stream_to_vector_0, '0', fft_vxx_0, '0'] 1027 | - [blocks_sub_xx_0, '0', blocks_stream_to_vector_0, '0'] 1028 | - [fft_vxx_0, '0', blocks_complex_to_mag_squared_0, '0'] 1029 | - [osmosdr_source_0, '0', blocks_head_0, '0'] 1030 | 1031 | metadata: 1032 | file_format: 1 1033 | -------------------------------------------------------------------------------- /noisemon/readme.md: -------------------------------------------------------------------------------- 1 | # Noisemon 2 | Noisemon is a rewrite of specmon, with the goal to measure noiselevels. 3 | The definition of noisemeasurements is stated in ITU documents, ITU-P SM.372-16, ITU-R SM.2055 and specific SM.1753-2. 4 | Based upon the above mentioned documents, multiple types of noise are identified: 5 | 6 | - WGN, or White Gaussian Noise 7 | - SCN, or Single Carrier Noise 8 | - IN, or Impulse Noise 9 | 10 | Besides identification of noise-types, normal usage of the frequency band is identified, based upon the assumption of minimum bandwidth for transmissions, as described in the ITU documents. 11 | 12 | The use of noisemon is to measure and display several types of noise over a long period of time. Measurements are taken every 200ms, or five times per second. 13 | 14 | ## Preparation 15 | The preparation for noisemon measurements is equal to setting up measurements with Specmon. 16 | 17 | ### RBW 18 | According to the ITU documentation for noise measurements, the RBW should be 500Hz or less. Using this RBW, Single Carrier Noise can be identified, based on the FFT's active on the detected signal. 19 | Using 2MSps and thus monitoring 2MHz of bandwidth, this requires an FFT-size of 4096. This yields to an RBW of 488Hz. 20 | When very smallband transmissions are expected, the FFT-size must be increased. 21 | 22 | ### Filtering 23 | When insufficient filtering is applied, spurious signals can be seen in the spectrum. This results in false measurements of SCN. Strong nearby signals can increase the overall noisefloor. If the selected SDR features analogue low-pass filters, it is advised to apply them. Not all SDR's have them but the PlutoSDR and LimeSDR Mini are two SDR with this features. 24 | 25 | 26 | ### Determine the threshold 27 | The threshold is the powerlevel value which a transmission should reach before it is considered as a transmission. According to the ITU it should be 20dB above the noise level however this is a high limit for relative low power transmissions or weak transmissions, caused by a higher free-space path loss. These latter transmissions are not recorded as transmissions with a high threshold. Using a low threshold on the other hand will cause false positives due to short term impulses, caused by RFI or noisefloor variances. 28 | The threshold can be controlled either afterwards using a replay from previous monitoring or by inspecting the measurements using specreceive. 29 | The default dynamic threshold is set to 8dB above the median noise level. 30 | 31 | ### SCN Limit 32 | An experimental option is available in noisemon. Detecting Single Carrier Noise is achieved by measuring the amount of adjacent FFT-bins above the threshold. SCN should only activate one FFT-bin but due to FFT-leakage, for example caused by the carrier not being in the middle of the FFT-bin, more FFT-bins can be activated. Some experiments show that 3 FFT's is a reasonable value, if the FFT-size is 500Hz or less. This 500Hz limit is defined by the ITU. 33 | 34 | ## Monitoring 35 | The monitoring is setup via cron using the tool `nmonit`. 36 | Edit nmonit with the required settings: 37 | 38 | ```` 39 | # Put to 1 to make this run 40 | ENABLED=1 41 | 42 | # Put to 1 to automatic clean old recordings in /tmp 43 | # Files older than 2 days are removed 44 | AUTOCLEAN=1 45 | 46 | GAIN=40 47 | FREQ=145e6 48 | RUNTIME=3580 49 | DEVICE="airspy=0" 50 | SAMPRATE=2e6 51 | #CALVEC=/home/user/noisemon/220911-143M-G40-S2e6-4096-0.calvec 52 | CALVEC=/home/user/noisemon/221014-145M-G40-S2e6-4096-0.calvec 53 | FFTSIZE=4096 54 | SCNLIMIT=3 55 | 56 | # Use the correct tool to run 57 | NOISEMON=/home/user/noisemon/noisemon.py 58 | 59 | # Define the logdir 60 | LOGDIR=/home/user/log/145 61 | ```` 62 | 63 | 64 | Please be aware of the runtime. It defaults to 3590 seconds instead of 3600 seconds. Starting and stopping the measurement takes some seconds, as the SDR needs to be initialized. Running the tool with 3600 results in running just over an hour and preventing the next hour to start the measurement. 65 | 66 | 67 | Run monit via cron: 68 | 69 | `0 * * * * /home/user/specmon/nmonit` 70 | 71 | ## Postprocessing 72 | Postprocessing on the logfiles can be executed manual or via cron. 73 | 74 | ### Noisegraph 75 | Manual creation of the graphs can be done using: 76 | 77 | ```` 78 | for i in noisemon-YYMMDD-{00..23}00.csv; do ./noisegraph ; done 79 | ```` 80 | 81 | This creates multiple graphs from the measurements: 82 | 83 | 1. `noisemon-YYMMDD-HHMM.csv-combined.png` Combined graph with noiselevel, Standard deviation of the noise, difference between mean and median and skewness of the noise. 84 | 2. `noisemon-YYMMDD-HHMM.csv-diff.png` Graph with the difference between the median and the mean of the measured noise. 85 | 3. `noisemon-YYMMDD-HHMM.csv-noise.png` Graph with the measured noise. 86 | 4. `noisemon-YYMMDD-HHMM.csv-skew.png` Graph with the skewness of the measured noise. 87 | 5. `noisemon-YYMMDD-HHMM.csv-std.png` Graph with the standard deviation of the measured noise. 88 | 6. `noisemon-YYMMDD-HHMM.csv-use-scn.png` Graph with the amount of normal usage and Single Carrier Noise, as calculated. 89 | 90 | 91 | ### Dayboxer 92 | Using the script `dayboxer` a graph is made with boxplots of the measured noise. This graph hold 24 boxplots and shows the spreading of the noise over the day. 93 | Dayboxer default print graphs from "yesterday" but other dates can be processed: 94 | 95 | `./dayboxer YYMMDD` 96 | 97 | Dayboxer default writes the graphs to the directory `tst/` in the current directory. This can be modified in the script. 98 | 99 | ## Data format 100 | The logfiles from noisemon are written to the log directory as configured in the nmonit wrapper. 101 | Data in this files are stored as csv, comma separated values. The format of the file is as follows: 102 | 103 | ```` 104 | Start,1667473204.96,Hour,12,Veclen,4096,Threshold,8.00,SCNLimit,3 105 | N,time,lowlimit,veccount,scncount,nusage,vecmean,vecstd,vecskew,rms,inoise,diff 106 | N,1667473207.47,8.56,1,8,4,8.48,0.44,-1.51,8.49,0,0.12 107 | N,1667473207.64,8.66,2,8,4,8.58,0.40,-1.10,8.59,0,0.12 108 | ```` 109 | 110 | The first line is the Start line. This writes: 111 | 112 | 1. The starting time in unix timestamp 113 | 2. Hour: The hour in which the measurement is started 114 | 3. Veclen: Used FFT-size (length of the vector) 115 | 4. Threshold: Threshold value above the noise. Adopted when the noiselevel changes 116 | 5. SCNLimit: Amount of FFT-bin's which can count as SCN. More than this is counted as normal usage 117 | 118 | The second line is the dataformat of the measured values. All values are calculated on a subset of the entire vector, named noisevector: 119 | 120 | 1. N: Noisemon 121 | 2. time: Time of the measurement in Unix timestamp 122 | 3. lowlimit: The median of the noisevector. The threshold is determined on this value 123 | 4. veccount: Count of measurements in this run 124 | 5. scncount: Counted SCN spikes 125 | 6. nusage: Counted "Normal usage" (wider than SCN) 126 | 7. vecmean: Mean of the noisevector. 127 | 8. vecstd: Standard Deviation in the noisevector. 128 | 9. vecskew: Skewness of the noisevector. 129 | 10. rms: RMS value of the noisevector. 130 | 11. inoise: Value for the (experimental) detection of Impulse Noise. 1 for INoise 131 | 12. diff: Absolute difference between the median(lowlimit) and mean(vecmean) 132 | 133 | -------------------------------------------------------------------------------- /parselog: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Description: Wrapper to automate the parsing of the individual logfiles to 4 | # combined daily logs 5 | # 6 | # Author: Bart Somers PE1RIK 7 | # 8 | 9 | LOGDIR=/home/pi/log 10 | DATESTRING=`date --date=yesterday +%y%m%d` 11 | OUTSTRING=`date +%y%m%d` 12 | LOGPREFIX=specmon2 13 | ENABLED=1 14 | TESTSPEC=/home/pi/specmon/testspec 15 | MKGRAPH=/home/pi/specmon/mkgraph 16 | 17 | if [ ${ENABLED} == 1 ]; then 18 | for i in `ls ${LOGDIR}/${LOGPREFIX}-${DATESTRING}*csv`; do 19 | 20 | ${TESTSPEC} -i $i -o ${LOGDIR}/${DATESTRING}.plot; 21 | done 22 | 23 | ${MKGRAPH} ${LOGDIR}/${DATESTRING}.plot 24 | 25 | fi 26 | 27 | 28 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Specmon 2 2 | Specmon 2 is a rewrite of the original Specmon, version 1. 3 | The goal of this project is to enable **Spec**trum **Mon**itoring over a long period of time while logging short-term activities. 4 | Using this combined logging over time it is possible to generate statistical usage over time. 5 | When plotting these results, usage statistics and usage patterns becomes visible. 6 | 7 | ## Requirements 8 | Specmon is based on SDR techniques. A suitable Software Defined Radio receiver is required to run the software. As Specmon is written in GNURadio, all the supported SDR's are usable with this software. 9 | Besides the SDR, an antenna for the spectrum under investigation is required. 10 | As most SDR's lack good frontend-filtering, bandfiltering is required to maintain reliable results. 11 | 12 | ### Dependencies 13 | Specmon is build upon GNURadio, Python and Gnuplot. 14 | For Debian-based systems the dependencies can be installed with: 15 | 16 | `apt install gnuradio gr-osmosdr python-pil rtl-sdr python3-scipy python3-numpy python3-matplotlib csvkit paste gnuplot` 17 | 18 | For support for other SDR's, install the required modules. For example for PlutoSDR: 19 | 20 | `apt install libiio0 libad9361-0 gr-iio` 21 | 22 | When using another SDR than the supported radio's under OsmoSDR, modify the flowgraph accordingly. 23 | 24 | ## Preparation 25 | Several steps are required to run specmon2: 26 | 27 | 1. Define the frequency band to monitor. For example: 2M HAM band, 144-146 MHz 28 | 2. Define the required sample-rate. In this case 2Msps. 29 | 3. Select the minimum frequency-size to trigger on: In this case FT8 as smallband mode needs to trigger the measurement. Using an FFT-size of 2048 results in a minimum monitoring of approx 1KHz (976Hz) 30 | 4. Calibrate the receiver and create a calibration vector for the measurement. The process of calibration is described seperately. 31 | 5. Determine the threshold for the measurement using live monitoring. 32 | 6. Setup the monitoring 33 | 34 | The gain settings of your SDR are highly dependent on the local environment and the antenna. Please use a low to moderate gain setting and use bandfilters to prevent overloading or images by out of band signals. 35 | 36 | ## Calibration 37 | Calibration is the process of alignment of the spectrum to the same value: That is, correcting the vector of FFT's to the same baseline. This generates a "flat spectrum". With this flat spectrum a single threshold value can be used during the monitoring process. 38 | 39 | Steps to take (in this order): 40 | 41 | ### Zero vector 42 | Create a "zero" vector with the correct FFT-size and a constant value of zero: 43 | 44 | `./calvec -o zero-calvec-2048.vec -l 2048 -c 0` 45 | 46 | This generates a file named zero-calvec-2048.vec with a "zero calibration" vector to use in the process. 47 | 48 | ### Dummy load measurement 49 | Connect the SDR to a dummyload to run this step. This is required as this corrects the spectrum. 50 | Run specmon2 for a minute with the required settings and record the vectors. These vectors are used to create the final calibration-vector: 51 | 52 | `./specmon2.py -g 20 -f 145e6 -s 2e6 -c zero-calvec-2048.vec -F 2048 -d rtl=0 -R 60` 53 | 54 | Setting the threshold is not required yet. 55 | 56 | ### Create the calibration vector 57 | From the output, written in /tmp on the filesystem, generate the calibration vector: 58 | 59 | `./calvec -i /tmp/210512-0641-145000000-2000000-2048.pvector -o 210521-145e6-2e6-2048-2.vec -l 2048 -c 2` 60 | 61 | This generates a calibration-vector: 62 | 63 | - With length 2048 64 | - With a constant 2 added to the values (lifting the spectrum) 65 | - Created on May 21th 2021 06:41 66 | - For frequency 145MHz 67 | - And samplerate 2Msps 68 | 69 | This calibration-vector is used for the monitoring process 70 | 71 | ### Determine the threshold 72 | The threshold is the powerlevel value which a transmission should reach before it is considered as a transmission. According to the ITU it should be 20dB above the noise level however this is a high limit for relative low power transmissions or weak transmissions, caused by a higher free-space path loss. These latter transmissions are not recorded as transmissions with a high threshold. Using a low threshold on the other hand will cause false positives due to short term impulses, caused by RFI or noisefloor variances. 73 | The threshold can be controlled either afterwards using a replay from previous monitoring or by inspecting the measurements using specmon_gui. 74 | 75 | #### Auto Threshold calculation 76 | Specmon2 is capable of adjusting the threshold value, based on the variances in the measured noise. The value passed to the parameter "threshold" is considered as the value above the measured noise level. During the monitoring process the actual threshold is adopted and printed in the raw measurement files. 77 | 78 | ## Monitoring 79 | The monitoring is setup via cron using the tool `monit2`. 80 | Edit monit2 with the required settings: 81 | 82 | ```` 83 | # Put to 1 to make this run 84 | ENABLED=1 85 | 86 | # Put to 1 to automatic clean old recordings in /tmp 87 | # Files older than 2 days are removed 88 | AUTOCLEAN=1 89 | 90 | THRESHOLD=8.0 91 | GAIN=20 92 | FREQ=145e6 93 | RUNTIME=3590 94 | DEVICE="rtl=0" 95 | SAMPRATE=2e6 96 | CALVEC=/home/pi/specmon/210504-calvec-145M-2e6-2048-0.vec 97 | FFTSIZE=2048 98 | 99 | # Use the correct tool to run 100 | SPECMON=/home/pi/specmon/specmon2.py 101 | 102 | LOGDIR=/home/pi/log/145 103 | ```` 104 | Please be aware of the runtime. It defaults to 3590 seconds instead of 3600 seconds. Starting and stopping the measurement takes some seconds, as the SDR needs to be initialized. Running the tool with 3600 results in running just over an hour and preventing the next hour to start the measurement. 105 | 106 | 107 | Run monit via cron: 108 | 109 | `0 * * * * /home/pi/specmon/monit2` 110 | 111 | ## Postprocessing 112 | Postprocessing the logfiles can be automated with `parselog`. 113 | Check the settings in this file and run via cron: 114 | 115 | `0 1 * * * /home/pi/specmon/parselog` 116 | 117 | This needs to run only once a day and will generate the graphs for the previous day: 118 | 119 | 1. `YYMMDD.plot-avgopen.png` : Average time in seconds above the threshold. 120 | 2. `YYMMDD.plot-maxopen.png` : Maximum measured value above the threshold. 121 | 3. `YYMMDD.plot-opening.png` : Number of times the threshold is triggered. 122 | 4. `YYMMDD.plot-percent.png` : Percentage of time the threshold is triggered. 123 | 124 | ### Weekly or monthly graphs 125 | Weekly or monthly graphs can manually be made by combine the daily logs to one large file: 126 | 127 | `cat 2105*.plot >> May2021.plot` 128 | And create a monthly graph with mgraph: 129 | 130 | `./mgraph May2021.plot` 131 | 132 | ## Specmon GUI 133 | Specmon2 can run graphical with `specmon2_gui`. This does not log all the output but the spectrum and the vectors of the flattend spectrum are displayed, together with the threshold. 134 | Specmon2_gui can be used to inspect the spectrum and select the right constant for the calibration-vector. 135 | 136 | ## Live view of data 137 | During the monitoring process, it is possible to connect to the ZMQ port for live view of the data, that are the vectors to be processed by specmon, remotely. 138 | For this a tool is added, specreceive, which can connect to the ZMQ port 50001, on the system, running specmon. 139 | As this only sends the integrated vectors, the amount is data is fairly low and can be send over a VPN or remote connection. 140 | 141 | ### Specreceive display 142 | Specreceive has two main displays: 143 | The first display, in the tab Spectrum, the current spectrum view is displayed. 144 | In addition to the spectrum, two more lines are drwan: 145 | 146 | 1. The green line is the "sorted spectrum", that is sorting the vector from low to high. 147 | 2. Based on the median of the lower half of the sorted spectrum (green line) the threshold is calculated. 148 | 149 | The second display is a waterfall display of the spectrum. 150 | 151 | ## Replay of recorded data 152 | The unprocessed vectors from the measurements are stored in /tmp. The vectors are not corrected yet with the calibration vector and thus named "unprocessed". These files can be graphical replayed, together with the calibration-vector to review the state while recorded. This can show RFI or other unknown transmissions, or can be used to modify the threshold value. 153 | 154 | ## Tools overview 155 | The following tools are included in this toolkit: 156 | 157 | ### specmon2 158 | The commandline tool for long term monitoring 159 | 160 | #### Options 161 | 162 | ```` 163 | usage: specmon2.py [-h] [-b BBGAIN] [-c CALIBVEC] [-d DEVICEID] [-F FFTSIZE] [-f FREQ] [-O OUTFILE] [-g RFGAIN] [-R RUNTIME] 164 | [-s SAMP_RATE] [-T THRESHOLD] [-v VERBOSE] 165 | 166 | optional arguments: 167 | -h, --help show this help message and exit 168 | -b BBGAIN, --bbgain BBGAIN 169 | Set BB-Gain [default=30] 170 | -c CALIBVEC, --calibvec CALIBVEC 171 | Set Calibration Vector [default='0'] 172 | -d DEVICEID, --deviceid DEVICEID 173 | Set Device ID [default='rtl=00000201'] 174 | -F FFTSIZE, --fftsize FFTSIZE 175 | Set FFT size [default=1024] 176 | -f FREQ, --freq FREQ Set Frequency [default='145.0M'] 177 | -O OUTFILE, --outfile OUTFILE 178 | Set Output File [default='/tmp/logfile.csv'] 179 | -g RFGAIN, --rfgain RFGAIN 180 | Set RF-Gain [default=40] 181 | -R RUNTIME, --runtime RUNTIME 182 | Set runtime [default=3590] 183 | -s SAMP_RATE, --samp-rate SAMP_RATE 184 | Set Sample Rate [default='2.0M'] 185 | -T THRESHOLD, --threshold THRESHOLD 186 | Set Threshold [default='100.0m'] 187 | -v VERBOSE, --verbose VERBOSE 188 | Set Print verbose values [default=0] 189 | ```` 190 | 191 | ### Specmon2_gui 192 | Specmon2 but with graphical display. To be used for manual monitoring and tuning of parameters 193 | 194 | #### Options 195 | 196 | ```` 197 | usage: specmon2_gui.py [-h] [-b BBGAIN] [-c CALIBVEC] [-d DEVICEID] [-F FFTSIZE] [-O OUTFILE] [-R RUNTIME] [-s SAMP_RATE] 198 | [-v VERBOSE] 199 | 200 | optional arguments: 201 | -h, --help show this help message and exit 202 | -b BBGAIN, --bbgain BBGAIN 203 | Set BB-Gain [default=30] 204 | -c CALIBVEC, --calibvec CALIBVEC 205 | Set Calibration Vector [default='/home/bart/grc/210926-zero-2048.vec'] 206 | -d DEVICEID, --deviceid DEVICEID 207 | Set Device ID [default='rtl=0'] 208 | -F FFTSIZE, --fftsize FFTSIZE 209 | Set FFT size [default=1024] 210 | -O OUTFILE, --outfile OUTFILE 211 | Set Output File [default='/tmp/logfile.csv'] 212 | -R RUNTIME, --runtime RUNTIME 213 | Set runtime [default=3590] 214 | -s SAMP_RATE, --samp-rate SAMP_RATE 215 | Set Sample Rate [default='2.0M'] 216 | -v VERBOSE, --verbose VERBOSE 217 | Set Print verbose values [default=0] 218 | ```` 219 | 220 | ### calvec 221 | Tool to create calibration vector, based on real measurement-data or a constant vector. 222 | 223 | #### Options 224 | 225 | ```` 226 | usage: calvec [-h] [-i INFILE] -o OUTFILE -c CONSTANT -l LENGTH 227 | 228 | optional arguments: 229 | -h, --help show this help message and exit 230 | -i INFILE, --infile INFILE 231 | Filename with vectors 232 | -o OUTFILE, --outfile OUTFILE 233 | Filename where to put output 234 | -c CONSTANT, --constant CONSTANT 235 | Constant to use for calculation 236 | -l LENGTH, --length LENGTH 237 | Vector-length to parse 238 | 239 | ```` 240 | 241 | ### mkgraph 242 | This tool is used to create the graphs from the parsed data. 243 | Usage: `./mkgraph ` 244 | 245 | ### monit2 246 | Shellscript to automate monitoring and cleanup from old loggings. The usage of monit2 is described above 247 | 248 | ### mgraph 249 | Shellscript to generate the monthly-graph from the concatenated logfiles. 250 | Usage: `./mgraph ` 251 | 252 | ### parselog 253 | Shellscript to automate the parsing of logfiles and creation of the graphs. To be run from cron so no options required. 254 | See the shellscript for the correct paths. 255 | 256 | ### testspec 257 | This is the parser for the logfiles from specmon2. It is called from parselog but can be used manually too. 258 | 259 | #### Options 260 | 261 | ```` 262 | usage: calvec [-h] [-i INFILE] -o OUTFILE -c CONSTANT -l LENGTH 263 | 264 | optional arguments: 265 | -h, --help show this help message and exit 266 | -i INFILE, --infile INFILE 267 | Filename with vectors 268 | -o OUTFILE, --outfile OUTFILE 269 | Filename where to put output 270 | -c CONSTANT, --constant CONSTANT 271 | Constant to use for calculation 272 | -l LENGTH, --length LENGTH 273 | Vector-length to parse 274 | 275 | ```` 276 | 277 | ### specreceive 278 | This is the ZMQ receiver for live remote view. 279 | Specreceive does not have commandline options but the flowgraph holds multiple variables which need to be set before running the flowgrapgh. 280 | The options required to correct are: 281 | 282 | - FFT size 283 | - Frequency 284 | - Sample Rate 285 | - Hostname or IP to connect to, in the ZMQ source block. 286 | + This should be in the format: `tcp://:50001` 287 | 288 | Specreceive also shows a line representing the threshold, which can be set manually using the slider. 289 | 290 | #### Options 291 | 292 | ```` 293 | usage: specreceive.py [-h] [-c CALCONST] [-F FFTSIZE] [-f FREQ] [-r REMOTE] [-s SAMP_RATE] 294 | 295 | optional arguments: 296 | -h, --help show this help message and exit 297 | -c CALCONST, --calconst CALCONST 298 | Set calibration-constant [default='-132.0'] 299 | -F FFTSIZE, --fftsize FFTSIZE 300 | Set fft-size [default=4096] 301 | -f FREQ, --freq FREQ Set Frequency [default='48.0M'] 302 | -r REMOTE, --remote REMOTE 303 | Set remote-host [default='tcp://remote:50001'] 304 | -s SAMP_RATE, --samp-rate SAMP_RATE 305 | Set Sample-Rate [default='2.5M'] 306 | ```` 307 | 308 | ## Usage suggestions 309 | Below are some suggestions to use the software. These suggestions are focused on the HAM-radio bands but probably other bands can monitored too. 310 | 311 | ### 2M HAM band 312 | 313 | - Frequency : 144 - 146 MHz 314 | - Tuner frequency: 145e6 315 | - Sample rate : 2e6 316 | - FFT-size: 2048 / 4096 317 | 318 | ### 6M HAM band 319 | 320 | - Frequency : 50 - 52 MHz 321 | - Tuner frequency : 51e6 322 | - Sample rate : 2e6 323 | - FFT-size : 2048 / 4096 324 | 325 | ### 70cm HAM band 326 | This band is 10MHz wide. The sample-rate must be supported by your SDR. A LimeSDR mini or Airspy R2 support this. This combination of sample rate and FFT-size is likely too much for a Raspberry Pi. 327 | 328 | - Frequency : 430 - 440 MHz 329 | - Tuner frequency : 435e6 330 | - Sample rate : 10e6 331 | - FFT-size : 16384 332 | 333 | ### EU 868MHz ISM band 334 | This band is wider than the suggested 2.5MHz but it holds the majority of the LoRa frequencies. Using this settings, the IOT usage can be monitored. As the LoRa transmissions are at least 125KHz wide, the FFT-size is sufficient for this monitoring. 335 | 336 | - Tuner frequency : 868.35MHz 337 | - Sample rate : 2.5e6 338 | - FFT-size : 2048 339 | 340 | -------------------------------------------------------------------------------- /specmon-v1.md: -------------------------------------------------------------------------------- 1 | # SPECMON 2 | 3 | Specmon is a set of tools for statistical **spec**trum **mon**itoring. It's designed for long-term monitoring and reporting usage statistics for the selected frequency-range. 4 | Specmon is not capable of recording transmissions in any way. 5 | 6 | 7 | ## The software 8 | The main tool is written in GNUradio [[5]]. Postprocessing is done in Python and graphs are plotted in GNUplot. The platforms used are Debian 10 and Raspbian 10. 9 | When running headless on a Raspberry Pi, a Raspberry Pi 3 or better is required. 10 | 11 | ### Dependencies 12 | 13 | `apt install gnuradio gnuplot gr-osmosdr`
14 | This dependencies allows you to use [RTL-SDR] , [HackRF], and [BladeRF]. If you need support for your specific SDR, you need to install the dependencies too.
If you need support for [PlutoSDR], you need to install the next dependencies: 15 | `apt install libiio0 libad9361-0 gr-iio` 16 | 17 | The default palette for the graphs can be changed by loading an additional palette from [gnuplot-palettes]. The weekgraphs are made with 'reds.pal' 18 | 19 | ## Running the software 20 | 21 | Running the software is quite easy but requires some preparations: 22 | 23 | 1. Choose the frequency to be monitored 24 | 2. Determine the required bandwidth, sample-rate and decimation 25 | - This defines the centre-frequency, or frequency to tune the SDR to. 26 | 3. Determine the threshold 27 | 4. Select the time to run. Default is 3590 seconds. 28 | 29 | The default runtime is 10 seconds less than one hour. This is to prevent the software is starting up again while just finishing the last measurement. 30 | 31 | ### Example 32 | 33 | We want to monitor the European PMR (Public Mobile Radio) band [[4]]. The defined frequency-range is 446.0 - 446.2 MHz so 200KHz bandwith. 34 | The center-frequency is 446.1MHz. You need to tune the SDR to this frequency. 35 | The required sample-rate should be 200.000 samples per second (200ksps). With the decimation-option this samplerate is created: Sample-rate 2Msps and a decimation 10 results in exactly 200.000 samples per second. 36 | 37 | I advice you to first run the GUI version to visual inspect the selected spectrum and to determine the threshold. From within Gnuradio-Companion, run specmon.grc, select the frequency (446.1e6), sample-rate (2e6), decimation (10) and run the flowchart. 38 | 39 | All depending on your SDR, gain, antenna and environment you can see the threshold drop when the frequency-band is idle. Take note of this value and increase it a little bit. For example, if it's idling around 0.75, increase to about 0.9 to prevent false-positives but prevent missing-out some band-usage. 40 | 41 | ### Running the software headless 42 | 43 | Specmon is designed to run one hour and restart for a new logfile. The previous logfile can be postprocessed and converted to a graph. 44 | 45 | "Compile" the flowgraph for headless monitoring to the python-file: 46 | `user@system:~$ grcc -d . specmon-cli.grc` 47 | 48 | On your headless system run the software: 49 | 50 | `./specmon-cli.py -f 446.1e6 -s 2e6 -D 10 -g 30 -T 0.8` 51 | And you should see lines like this: 52 | 53 | `A,1.1,1576821964.22,U,2.8,1576821964.78` 54 | 55 | - A is *Above*, 56 | - 1.1 is the average low-value since the last measurement, 57 | - 1576821964.22 is the timestamp, 58 | - U is *Under* the threshold, 59 | - 2.8 is the maximum value reached during this trigger, 60 | - 1576821964.78 is the timestamp when dropped below the threshold. 61 | 62 | 63 | If you are happy with the result, start running it from cron and let it run for several days: 64 | 65 | ```` 66 | crontab -l 67 | # m h dom mon dow command 68 | 0 * * * * /home/pi/bin/monit 69 | ```` 70 | The script monit is provided in the source-tree. This runs the tool for an hour and creates a logfile per hour. 71 | Additionaly it creates a logfile with end-time of the script and (for a Raspberry Pi) the temperature. This option is default disabled. 72 | 73 | ### Postprocessing the data 74 | After running for 24 hours you can make a graph for the usage-statistics. Therefor you need to postprocess the data using "testspec": 75 | 76 | ```` 77 | for i in `ls log/specmon2-200110*csv`; do ./testspec $i >> log/200110.log ; done 78 | ```` 79 | And now plot the graphs: 80 | `./mkgraph 200110.log` 81 | This results in 3 graphs: 82 | 83 | + 200110.log-opening.png with the number of openings 84 | + 200110.log-percent.png with the percentage of time "open" or "used" 85 | + 200110.log-avgopen.png with the average time "open" 86 | 87 | View the graphs in your viewer. 88 | After the first week you can see patterns of usage over the week. After several weeks you start seeing patterns per day. First combine a week of data: 89 | `cat day1.log day2.log day3.log day4.log day5.log day6.log day7.log >> week.log` 90 | and plot a 3D graph for the week: 91 | `./weekgraph week.log` 92 | This creates a 3D plot over the entire week. 93 | 94 | --- 95 | ## Some suggestions for use 96 | ### Frequency suggestions 97 | **EU 70cm analog repeaters:** 98 | 99 | - Downlink: 430.000 - 430.400 MHz 100 | - Center-frequency: 430.200 MHz 101 | - Sample-rate: 2e6 102 | - Decimation: 5 103 | 104 | **EU 70cm DMR repeater:** 105 | 106 | - Downlink: 438.000 - 438.400 MHz 107 | - Center-frequency: 438.200 MHz 108 | - Sample-rate: 2e6 109 | - Decimation: 5 110 | 111 | **EU 2M analog repeaters:** 112 | 113 | - Downlink: 145.600 - 145.800 MHz 114 | - Center-frequency: 145.700 MHz 115 | - Sample-rate: 2e6 116 | - Decimation: 10 117 | 118 | **EU PMR446 [[4]]:** 119 | 120 | - Frequency span: 446.000 - 446.200 MHz 121 | - Center-frequency: 446.100 MHz 122 | - Sample-rate: 2e6 123 | - Decimation: 10 124 | 125 | Since the revision of june 2020 small bursts can trigger specmon and measured. AIS bursts are very short but can be measured. Settings are: 126 | 127 | **AIS bursts:** 128 | 129 | - Frequency span: 161.950 - 162.050 MHz 130 | - Center-frequency: 162.000 MHz 131 | - Sample-rate: 2e6 132 | - Decimation: 20 133 | 134 | 135 | ### Verbose mode 136 | Determining the threshold can also be achieved in headless mode. Run specmon_cli.py with the `-v 1` option. 137 | See `specmon_cli.py -h` for all the options. 138 | 139 | ### GNUradio 3.7 vs 3.8 140 | Although GNUradio 3.8 has been released for a while, i'm still using 3.7 branch. Why, would you ask. Pretty easy: Installing GNUradio on a raspberry pi for the headless mode is quite easy as it's in the repository. But it's the maintained 3.7 branch. 141 | 142 | ### Other SDR's 143 | You can select other SDR's to use. Currently specmon is build around the Osmocom-Source so every SDR supported in this block, can be used: 144 | `-d rtl=00000234` for RTL-dongle with serial 234
145 | `-d bladerf=0` for the first bladerf connected
146 | `-d hackrf=0` for the first hackrf connected
147 | 148 | For other SDR's the source-block in the Gnuradio Flowgraph needs to be exchanged. 149 | 150 | ## Help 151 | 152 | ```` 153 | Usage: specmon_cli.py: [options] 154 | 155 | Options: 156 | -h, --help show this help message and exit 157 | -b BBGAIN, --bbgain=BBGAIN 158 | Set BB-Gain [default=30] 159 | -D DECIMATION, --decimation=DECIMATION 160 | Set Decimation [default=10] 161 | -d DEVICEID, --deviceid=DEVICEID 162 | Set Device ID [default=rtl=00000201] 163 | -f FREQ, --freq=FREQ Set Frequency [default=431.0M] 164 | -g RFGAIN, --rfgain=RFGAIN 165 | Set RF-Gain [default=30] 166 | -s SAMP_RATE, --samp-rate=SAMP_RATE 167 | Set Sample Rate [default=2.0M] 168 | -T THRESHOLD, --threshold=THRESHOLD 169 | Set Threshold [default=60.0] 170 | -v VERBOSE, --verbose=VERBOSE 171 | Set Verbose [default=0] 172 | -R RUNTIME, --runtime=RUNTIME 173 | Set Runtime in seconds [default=3590] 174 | ```` 175 | Be aware that sample-rate and frequency must be in scientific notation. For example: `-s 2e6 -D 10 -f 446.1e6`. 176 | 177 | ## Revisions 178 | August 2020: 179 | Some minor updates on documentation and the script for running specmon from cron. Printing 2 decimals to increase resolution in testspec. 180 | 181 | June 2020: 182 | Software is capable of measuring shorter bursts. 183 | Reporting now has an average of the "low values", i.e. under the threshold, since the last trigger of the threshold. 184 | Reporting the max value measured during the trigger of the threshold. 185 | 186 | [RTL-SDR]: https://www.rtl-sdr.com/buy-rtl-sdr-dvb-t-dongles/ 187 | [HackRF]: https://greatscottgadgets.com/hackrf/ 188 | [PlutoSDR]: https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/adalm-pluto.html#eb-overview 189 | [BladeRF]: https://www.nuand.com/ 190 | [4]: https://en.wikipedia.org/wiki/PMR446 191 | [5]: https://www.gnuradio.org/ 192 | [gnuplot-palettes]: https://github.com/Gnuplotting/gnuplot-palettes 193 | -------------------------------------------------------------------------------- /specmon2.grc: -------------------------------------------------------------------------------- 1 | options: 2 | parameters: 3 | author: PE1RIK 4 | category: '[GRC Hier Blocks]' 5 | cmake_opt: '' 6 | comment: '' 7 | copyright: '' 8 | description: '' 9 | gen_cmake: 'On' 10 | gen_linking: dynamic 11 | generate_options: no_gui 12 | hier_block_src_path: '.:' 13 | id: specmon2 14 | max_nouts: '0' 15 | output_language: python 16 | placement: (0,0) 17 | qt_qss_theme: '' 18 | realtime_scheduling: '' 19 | run: 'True' 20 | run_command: '{python} -u {filename}' 21 | run_options: run 22 | sizing_mode: fixed 23 | thread_safe_setters: '' 24 | title: '' 25 | window_size: '' 26 | states: 27 | bus_sink: false 28 | bus_source: false 29 | bus_structure: null 30 | coordinate: [8, 8] 31 | rotation: 0 32 | state: enabled 33 | 34 | blocks: 35 | - name: fhandler 36 | id: variable 37 | parameters: 38 | comment: '' 39 | value: '0' 40 | states: 41 | bus_sink: false 42 | bus_source: false 43 | bus_structure: null 44 | coordinate: [1232, 164.0] 45 | rotation: 0 46 | state: true 47 | - name: intcount 48 | id: variable 49 | parameters: 50 | comment: 'Integration count. 51 | 52 | Also used for normalisation 53 | 54 | 55 | vector_rate is vectors per second 56 | 57 | 58 | intcount = samp_rate/(fftsize * vector_rate) 59 | 60 | 61 | Bij vector_rate = 5 (200ms): 62 | 63 | 64 | intcount = samp_rate/(fftsize * 5)' 65 | value: int(samp_rate/(fftsize * 5)) 66 | states: 67 | bus_sink: false 68 | bus_source: false 69 | bus_structure: null 70 | coordinate: [880, 316.0] 71 | rotation: 0 72 | state: enabled 73 | - name: start_state 74 | id: variable 75 | parameters: 76 | comment: '' 77 | value: '0' 78 | states: 79 | bus_sink: false 80 | bus_source: false 81 | bus_structure: null 82 | coordinate: [624, 368] 83 | rotation: 0 84 | state: enabled 85 | - name: bbgain 86 | id: parameter 87 | parameters: 88 | alias: '' 89 | comment: '' 90 | hide: none 91 | label: BB-Gain 92 | short_id: b 93 | type: intx 94 | value: '30' 95 | states: 96 | bus_sink: false 97 | bus_source: false 98 | bus_structure: null 99 | coordinate: [632, 32] 100 | rotation: 0 101 | state: enabled 102 | - name: blocks_add_xx_0 103 | id: blocks_add_xx 104 | parameters: 105 | affinity: '' 106 | alias: '' 107 | comment: '' 108 | maxoutbuf: '0' 109 | minoutbuf: '0' 110 | num_inputs: '2' 111 | type: float 112 | vlen: fftsize 113 | states: 114 | bus_sink: false 115 | bus_source: false 116 | bus_structure: null 117 | coordinate: [240, 536] 118 | rotation: 180 119 | state: enabled 120 | - name: blocks_complex_to_mag_squared_0 121 | id: blocks_complex_to_mag_squared 122 | parameters: 123 | affinity: '' 124 | alias: '' 125 | comment: '' 126 | maxoutbuf: '0' 127 | minoutbuf: '0' 128 | vlen: fftsize 129 | states: 130 | bus_sink: false 131 | bus_source: false 132 | bus_structure: null 133 | coordinate: [1080, 544] 134 | rotation: 180 135 | state: enabled 136 | - name: blocks_file_sink_0 137 | id: blocks_file_sink 138 | parameters: 139 | affinity: '' 140 | alias: '' 141 | append: 'False' 142 | comment: 'Debug option to save vector before 143 | 144 | calibration and specmon2 logics' 145 | file: '"/tmp/" + time.strftime("%y%m%d-%H%M") + "-" + str(int(freq)) + "-" + str(int(samp_rate)) 146 | + "-" + str(fftsize) + ".pvector"' 147 | type: float 148 | unbuffered: 'False' 149 | vlen: fftsize 150 | states: 151 | bus_sink: false 152 | bus_source: false 153 | bus_structure: null 154 | coordinate: [184, 680] 155 | rotation: 180 156 | state: enabled 157 | - name: blocks_file_source_0 158 | id: blocks_file_source 159 | parameters: 160 | affinity: '' 161 | alias: '' 162 | begin_tag: pmt.PMT_NIL 163 | comment: '' 164 | file: calibvec 165 | length: '0' 166 | maxoutbuf: '0' 167 | minoutbuf: '0' 168 | offset: '0' 169 | repeat: 'True' 170 | type: float 171 | vlen: fftsize 172 | states: 173 | bus_sink: false 174 | bus_source: false 175 | bus_structure: null 176 | coordinate: [464, 696] 177 | rotation: 180 178 | state: enabled 179 | - name: blocks_head_0 180 | id: blocks_head 181 | parameters: 182 | affinity: '' 183 | alias: '' 184 | comment: '' 185 | maxoutbuf: '0' 186 | minoutbuf: '0' 187 | num_items: int(runtime*samp_rate) 188 | type: complex 189 | vlen: '1' 190 | states: 191 | bus_sink: false 192 | bus_source: false 193 | bus_structure: null 194 | coordinate: [320, 232.0] 195 | rotation: 0 196 | state: enabled 197 | - name: blocks_integrate_xx_0 198 | id: blocks_integrate_xx 199 | parameters: 200 | affinity: '' 201 | alias: '' 202 | comment: '' 203 | decim: intcount 204 | maxoutbuf: '0' 205 | minoutbuf: '0' 206 | type: float 207 | vlen: fftsize 208 | states: 209 | bus_sink: false 210 | bus_source: false 211 | bus_structure: null 212 | coordinate: [880, 536] 213 | rotation: 180 214 | state: enabled 215 | - name: blocks_moving_average_xx_0 216 | id: blocks_moving_average_xx 217 | parameters: 218 | affinity: '' 219 | alias: '' 220 | comment: '' 221 | length: '500' 222 | max_iter: '4000' 223 | maxoutbuf: '0' 224 | minoutbuf: '0' 225 | scale: 1.0/500 226 | type: complex 227 | vlen: '1' 228 | states: 229 | bus_sink: false 230 | bus_source: false 231 | bus_structure: null 232 | coordinate: [472, 288.0] 233 | rotation: 0 234 | state: enabled 235 | - name: blocks_multiply_const_vxx_0 236 | id: blocks_multiply_const_vxx 237 | parameters: 238 | affinity: '' 239 | alias: '' 240 | comment: Normalize integrated vectors 241 | const: '[1.0/intcount]*fftsize' 242 | maxoutbuf: '0' 243 | minoutbuf: '0' 244 | type: float 245 | vlen: fftsize 246 | states: 247 | bus_sink: false 248 | bus_source: false 249 | bus_structure: null 250 | coordinate: [648, 536] 251 | rotation: 180 252 | state: enabled 253 | - name: blocks_nlog10_ff_0 254 | id: blocks_nlog10_ff 255 | parameters: 256 | affinity: '' 257 | alias: '' 258 | comment: '' 259 | k: '0' 260 | maxoutbuf: '0' 261 | minoutbuf: '0' 262 | n: '10' 263 | vlen: fftsize 264 | states: 265 | bus_sink: false 266 | bus_source: false 267 | bus_structure: null 268 | coordinate: [456, 532] 269 | rotation: 180 270 | state: enabled 271 | - name: blocks_stream_to_vector_0 272 | id: blocks_stream_to_vector 273 | parameters: 274 | affinity: '' 275 | alias: '' 276 | comment: '' 277 | maxoutbuf: '0' 278 | minoutbuf: '0' 279 | num_items: fftsize 280 | type: complex 281 | vlen: '1' 282 | states: 283 | bus_sink: false 284 | bus_source: false 285 | bus_structure: null 286 | coordinate: [832, 248] 287 | rotation: 0 288 | state: enabled 289 | - name: blocks_sub_xx_0 290 | id: blocks_sub_xx 291 | parameters: 292 | affinity: '' 293 | alias: '' 294 | comment: '' 295 | maxoutbuf: '0' 296 | minoutbuf: '0' 297 | num_inputs: '2' 298 | type: complex 299 | vlen: '1' 300 | states: 301 | bus_sink: false 302 | bus_source: false 303 | bus_structure: null 304 | coordinate: [656, 224] 305 | rotation: 0 306 | state: enabled 307 | - name: calibvec 308 | id: parameter 309 | parameters: 310 | alias: '' 311 | comment: '' 312 | hide: none 313 | label: Calibration Vector 314 | short_id: c 315 | type: str 316 | value: '0' 317 | states: 318 | bus_sink: false 319 | bus_source: false 320 | bus_structure: null 321 | coordinate: [672, 656] 322 | rotation: 0 323 | state: enabled 324 | - name: deviceid 325 | id: parameter 326 | parameters: 327 | alias: '' 328 | comment: '' 329 | hide: none 330 | label: Device ID 331 | short_id: d 332 | type: str 333 | value: '"rtl=00000201"' 334 | states: 335 | bus_sink: false 336 | bus_source: false 337 | bus_structure: null 338 | coordinate: [240, 32] 339 | rotation: 0 340 | state: enabled 341 | - name: fft_vxx_0 342 | id: fft_vxx 343 | parameters: 344 | affinity: '' 345 | alias: '' 346 | comment: '' 347 | fft_size: fftsize 348 | forward: 'True' 349 | maxoutbuf: '0' 350 | minoutbuf: '0' 351 | nthreads: '1' 352 | shift: 'True' 353 | type: complex 354 | window: window.blackmanharris(fftsize) 355 | states: 356 | bus_sink: false 357 | bus_source: false 358 | bus_structure: null 359 | coordinate: [1024, 216] 360 | rotation: 0 361 | state: enabled 362 | - name: fftsize 363 | id: parameter 364 | parameters: 365 | alias: '' 366 | comment: '' 367 | hide: none 368 | label: FFT size 369 | short_id: F 370 | type: intx 371 | value: '1024' 372 | states: 373 | bus_sink: false 374 | bus_source: false 375 | bus_structure: null 376 | coordinate: [856, 652] 377 | rotation: 0 378 | state: enabled 379 | - name: freq 380 | id: parameter 381 | parameters: 382 | alias: '' 383 | comment: '' 384 | hide: none 385 | label: Frequency 386 | short_id: f 387 | type: eng_float 388 | value: 145e6 389 | states: 390 | bus_sink: false 391 | bus_source: false 392 | bus_structure: null 393 | coordinate: [392, 32] 394 | rotation: 0 395 | state: enabled 396 | - name: import_0 397 | id: import 398 | parameters: 399 | alias: '' 400 | comment: "Required when not \nusing osmocom source" 401 | imports: import time 402 | states: 403 | bus_sink: false 404 | bus_source: false 405 | bus_structure: null 406 | coordinate: [16, 680] 407 | rotation: 0 408 | state: enabled 409 | - name: osmosdr_source_0 410 | id: osmosdr_source 411 | parameters: 412 | affinity: '' 413 | alias: '' 414 | ant0: '' 415 | ant1: '' 416 | ant10: '' 417 | ant11: '' 418 | ant12: '' 419 | ant13: '' 420 | ant14: '' 421 | ant15: '' 422 | ant16: '' 423 | ant17: '' 424 | ant18: '' 425 | ant19: '' 426 | ant2: '' 427 | ant20: '' 428 | ant21: '' 429 | ant22: '' 430 | ant23: '' 431 | ant24: '' 432 | ant25: '' 433 | ant26: '' 434 | ant27: '' 435 | ant28: '' 436 | ant29: '' 437 | ant3: '' 438 | ant30: '' 439 | ant31: '' 440 | ant4: '' 441 | ant5: '' 442 | ant6: '' 443 | ant7: '' 444 | ant8: '' 445 | ant9: '' 446 | args: deviceid 447 | bb_gain0: bbgain 448 | bb_gain1: '20' 449 | bb_gain10: '20' 450 | bb_gain11: '20' 451 | bb_gain12: '20' 452 | bb_gain13: '20' 453 | bb_gain14: '20' 454 | bb_gain15: '20' 455 | bb_gain16: '20' 456 | bb_gain17: '20' 457 | bb_gain18: '20' 458 | bb_gain19: '20' 459 | bb_gain2: '20' 460 | bb_gain20: '20' 461 | bb_gain21: '20' 462 | bb_gain22: '20' 463 | bb_gain23: '20' 464 | bb_gain24: '20' 465 | bb_gain25: '20' 466 | bb_gain26: '20' 467 | bb_gain27: '20' 468 | bb_gain28: '20' 469 | bb_gain29: '20' 470 | bb_gain3: '20' 471 | bb_gain30: '20' 472 | bb_gain31: '20' 473 | bb_gain4: '20' 474 | bb_gain5: '20' 475 | bb_gain6: '20' 476 | bb_gain7: '20' 477 | bb_gain8: '20' 478 | bb_gain9: '20' 479 | bw0: '0' 480 | bw1: '0' 481 | bw10: '0' 482 | bw11: '0' 483 | bw12: '0' 484 | bw13: '0' 485 | bw14: '0' 486 | bw15: '0' 487 | bw16: '0' 488 | bw17: '0' 489 | bw18: '0' 490 | bw19: '0' 491 | bw2: '0' 492 | bw20: '0' 493 | bw21: '0' 494 | bw22: '0' 495 | bw23: '0' 496 | bw24: '0' 497 | bw25: '0' 498 | bw26: '0' 499 | bw27: '0' 500 | bw28: '0' 501 | bw29: '0' 502 | bw3: '0' 503 | bw30: '0' 504 | bw31: '0' 505 | bw4: '0' 506 | bw5: '0' 507 | bw6: '0' 508 | bw7: '0' 509 | bw8: '0' 510 | bw9: '0' 511 | clock_source0: '' 512 | clock_source1: '' 513 | clock_source2: '' 514 | clock_source3: '' 515 | clock_source4: '' 516 | clock_source5: '' 517 | clock_source6: '' 518 | clock_source7: '' 519 | comment: '' 520 | corr0: '0' 521 | corr1: '0' 522 | corr10: '0' 523 | corr11: '0' 524 | corr12: '0' 525 | corr13: '0' 526 | corr14: '0' 527 | corr15: '0' 528 | corr16: '0' 529 | corr17: '0' 530 | corr18: '0' 531 | corr19: '0' 532 | corr2: '0' 533 | corr20: '0' 534 | corr21: '0' 535 | corr22: '0' 536 | corr23: '0' 537 | corr24: '0' 538 | corr25: '0' 539 | corr26: '0' 540 | corr27: '0' 541 | corr28: '0' 542 | corr29: '0' 543 | corr3: '0' 544 | corr30: '0' 545 | corr31: '0' 546 | corr4: '0' 547 | corr5: '0' 548 | corr6: '0' 549 | corr7: '0' 550 | corr8: '0' 551 | corr9: '0' 552 | dc_offset_mode0: '0' 553 | dc_offset_mode1: '0' 554 | dc_offset_mode10: '0' 555 | dc_offset_mode11: '0' 556 | dc_offset_mode12: '0' 557 | dc_offset_mode13: '0' 558 | dc_offset_mode14: '0' 559 | dc_offset_mode15: '0' 560 | dc_offset_mode16: '0' 561 | dc_offset_mode17: '0' 562 | dc_offset_mode18: '0' 563 | dc_offset_mode19: '0' 564 | dc_offset_mode2: '0' 565 | dc_offset_mode20: '0' 566 | dc_offset_mode21: '0' 567 | dc_offset_mode22: '0' 568 | dc_offset_mode23: '0' 569 | dc_offset_mode24: '0' 570 | dc_offset_mode25: '0' 571 | dc_offset_mode26: '0' 572 | dc_offset_mode27: '0' 573 | dc_offset_mode28: '0' 574 | dc_offset_mode29: '0' 575 | dc_offset_mode3: '0' 576 | dc_offset_mode30: '0' 577 | dc_offset_mode31: '0' 578 | dc_offset_mode4: '0' 579 | dc_offset_mode5: '0' 580 | dc_offset_mode6: '0' 581 | dc_offset_mode7: '0' 582 | dc_offset_mode8: '0' 583 | dc_offset_mode9: '0' 584 | freq0: freq 585 | freq1: 100e6 586 | freq10: 100e6 587 | freq11: 100e6 588 | freq12: 100e6 589 | freq13: 100e6 590 | freq14: 100e6 591 | freq15: 100e6 592 | freq16: 100e6 593 | freq17: 100e6 594 | freq18: 100e6 595 | freq19: 100e6 596 | freq2: 100e6 597 | freq20: 100e6 598 | freq21: 100e6 599 | freq22: 100e6 600 | freq23: 100e6 601 | freq24: 100e6 602 | freq25: 100e6 603 | freq26: 100e6 604 | freq27: 100e6 605 | freq28: 100e6 606 | freq29: 100e6 607 | freq3: 100e6 608 | freq30: 100e6 609 | freq31: 100e6 610 | freq4: 100e6 611 | freq5: 100e6 612 | freq6: 100e6 613 | freq7: 100e6 614 | freq8: 100e6 615 | freq9: 100e6 616 | gain0: rfgain 617 | gain1: '10' 618 | gain10: '10' 619 | gain11: '10' 620 | gain12: '10' 621 | gain13: '10' 622 | gain14: '10' 623 | gain15: '10' 624 | gain16: '10' 625 | gain17: '10' 626 | gain18: '10' 627 | gain19: '10' 628 | gain2: '10' 629 | gain20: '10' 630 | gain21: '10' 631 | gain22: '10' 632 | gain23: '10' 633 | gain24: '10' 634 | gain25: '10' 635 | gain26: '10' 636 | gain27: '10' 637 | gain28: '10' 638 | gain29: '10' 639 | gain3: '10' 640 | gain30: '10' 641 | gain31: '10' 642 | gain4: '10' 643 | gain5: '10' 644 | gain6: '10' 645 | gain7: '10' 646 | gain8: '10' 647 | gain9: '10' 648 | gain_mode0: 'False' 649 | gain_mode1: 'False' 650 | gain_mode10: 'False' 651 | gain_mode11: 'False' 652 | gain_mode12: 'False' 653 | gain_mode13: 'False' 654 | gain_mode14: 'False' 655 | gain_mode15: 'False' 656 | gain_mode16: 'False' 657 | gain_mode17: 'False' 658 | gain_mode18: 'False' 659 | gain_mode19: 'False' 660 | gain_mode2: 'False' 661 | gain_mode20: 'False' 662 | gain_mode21: 'False' 663 | gain_mode22: 'False' 664 | gain_mode23: 'False' 665 | gain_mode24: 'False' 666 | gain_mode25: 'False' 667 | gain_mode26: 'False' 668 | gain_mode27: 'False' 669 | gain_mode28: 'False' 670 | gain_mode29: 'False' 671 | gain_mode3: 'False' 672 | gain_mode30: 'False' 673 | gain_mode31: 'False' 674 | gain_mode4: 'False' 675 | gain_mode5: 'False' 676 | gain_mode6: 'False' 677 | gain_mode7: 'False' 678 | gain_mode8: 'False' 679 | gain_mode9: 'False' 680 | if_gain0: '20' 681 | if_gain1: '20' 682 | if_gain10: '20' 683 | if_gain11: '20' 684 | if_gain12: '20' 685 | if_gain13: '20' 686 | if_gain14: '20' 687 | if_gain15: '20' 688 | if_gain16: '20' 689 | if_gain17: '20' 690 | if_gain18: '20' 691 | if_gain19: '20' 692 | if_gain2: '20' 693 | if_gain20: '20' 694 | if_gain21: '20' 695 | if_gain22: '20' 696 | if_gain23: '20' 697 | if_gain24: '20' 698 | if_gain25: '20' 699 | if_gain26: '20' 700 | if_gain27: '20' 701 | if_gain28: '20' 702 | if_gain29: '20' 703 | if_gain3: '20' 704 | if_gain30: '20' 705 | if_gain31: '20' 706 | if_gain4: '20' 707 | if_gain5: '20' 708 | if_gain6: '20' 709 | if_gain7: '20' 710 | if_gain8: '20' 711 | if_gain9: '20' 712 | iq_balance_mode0: '0' 713 | iq_balance_mode1: '0' 714 | iq_balance_mode10: '0' 715 | iq_balance_mode11: '0' 716 | iq_balance_mode12: '0' 717 | iq_balance_mode13: '0' 718 | iq_balance_mode14: '0' 719 | iq_balance_mode15: '0' 720 | iq_balance_mode16: '0' 721 | iq_balance_mode17: '0' 722 | iq_balance_mode18: '0' 723 | iq_balance_mode19: '0' 724 | iq_balance_mode2: '0' 725 | iq_balance_mode20: '0' 726 | iq_balance_mode21: '0' 727 | iq_balance_mode22: '0' 728 | iq_balance_mode23: '0' 729 | iq_balance_mode24: '0' 730 | iq_balance_mode25: '0' 731 | iq_balance_mode26: '0' 732 | iq_balance_mode27: '0' 733 | iq_balance_mode28: '0' 734 | iq_balance_mode29: '0' 735 | iq_balance_mode3: '0' 736 | iq_balance_mode30: '0' 737 | iq_balance_mode31: '0' 738 | iq_balance_mode4: '0' 739 | iq_balance_mode5: '0' 740 | iq_balance_mode6: '0' 741 | iq_balance_mode7: '0' 742 | iq_balance_mode8: '0' 743 | iq_balance_mode9: '0' 744 | maxoutbuf: '0' 745 | minoutbuf: '0' 746 | nchan: '1' 747 | num_mboards: '1' 748 | sample_rate: samp_rate 749 | sync: sync 750 | time_source0: '' 751 | time_source1: '' 752 | time_source2: '' 753 | time_source3: '' 754 | time_source4: '' 755 | time_source5: '' 756 | time_source6: '' 757 | time_source7: '' 758 | type: fc32 759 | states: 760 | bus_sink: false 761 | bus_source: false 762 | bus_structure: null 763 | coordinate: [0, 236.0] 764 | rotation: 0 765 | state: enabled 766 | - name: outfile 767 | id: parameter 768 | parameters: 769 | alias: '' 770 | comment: '' 771 | hide: none 772 | label: Output File 773 | short_id: O 774 | type: str 775 | value: '"/tmp/logfile.csv"' 776 | states: 777 | bus_sink: false 778 | bus_source: false 779 | bus_structure: null 780 | coordinate: [1192, 36.0] 781 | rotation: 0 782 | state: true 783 | - name: rfgain 784 | id: parameter 785 | parameters: 786 | alias: '' 787 | comment: '' 788 | hide: none 789 | label: RF-Gain 790 | short_id: g 791 | type: intx 792 | value: '40' 793 | states: 794 | bus_sink: false 795 | bus_source: false 796 | bus_structure: null 797 | coordinate: [520, 32] 798 | rotation: 0 799 | state: enabled 800 | - name: runtime 801 | id: parameter 802 | parameters: 803 | alias: '' 804 | comment: '' 805 | hide: none 806 | label: '' 807 | short_id: R 808 | type: intx 809 | value: '3590' 810 | states: 811 | bus_sink: false 812 | bus_source: false 813 | bus_structure: null 814 | coordinate: [320, 328.0] 815 | rotation: 0 816 | state: enabled 817 | - name: samp_rate 818 | id: parameter 819 | parameters: 820 | alias: '' 821 | comment: '' 822 | hide: none 823 | label: Sample Rate 824 | short_id: s 825 | type: eng_float 826 | value: 2e6 827 | states: 828 | bus_sink: false 829 | bus_source: false 830 | bus_structure: null 831 | coordinate: [872, 32] 832 | rotation: 0 833 | state: enabled 834 | - name: specmon_block 835 | id: epy_block 836 | parameters: 837 | _source_code: "\"\"\"\nEmbedded Python Blocks:\n\nEach time this file is saved,\ 838 | \ GRC will instantiate the first class it finds\nto get ports and parameters\ 839 | \ of your block. The arguments to __init__ will\nbe the parameters. All of\ 840 | \ them are required to have default values!\n\"\"\"\n\n#from __future__ import\ 841 | \ print_function\nimport numpy as np\nfrom gnuradio import gr\nimport time\n\ 842 | \n\nclass blk(gr.sync_block): # other base classes are basic_block, decim_block,\ 843 | \ interp_block\n \"\"\"Specmon data analysis block. \n This block is the\ 844 | \ improved version for specmon\n \"\"\"\n\n\t# Don't use \"logfile\" as varname\ 845 | \ as it's reserved in GRC\n def __init__(self, fftsize=1024, start_state=0,\ 846 | \ threshold=1.0, verbose=0, reportfile=\"/tmp/logfile.csv\"): # only default\ 847 | \ arguments here\n \"\"\"arguments to this function show up as parameters\ 848 | \ in GRC\"\"\"\n self.fftsize = fftsize\n self.start_state = start_state\n\ 849 | \ self.threshold = threshold\n self.verbose = verbose\n \ 850 | \ self.maxval = 0\n self.sumval = 0\n self.lowcounter = 1\n \ 851 | \ self.reportfile = reportfile\n gr.sync_block.__init__(\n \ 852 | \ self,\n name='Specmon2', # will show up in GRC\n \ 853 | \ in_sig=[(np.float32,self.fftsize)],\n out_sig=None\n \ 854 | \ )\n # Print startline\n self.outfile = open(reportfile, \"\ 855 | a\")\n print (\"S,%.2f,H,%s,T,%.2f\" % ( time.time(), str(time.strftime(\"\ 856 | %H\")), threshold ), file=self.outfile, flush=True )\n \n def work(self,\ 857 | \ input_items, output_items):\n \n for j in (range(len(input_items[0]))):\n\ 858 | \ if len(input_items[0][j]) == self.fftsize:\n speclist\ 859 | \ = np.array(input_items[0][0])\n # Peak for max-value\n \ 860 | \ curval = np.amax(speclist)\n # Median for median\ 861 | \ noise level\n noiseval = np.median(speclist)\n \ 862 | \ if self.verbose == 1:\n #print (\"%.2f\" % curval)\n\ 863 | \ print (\"Current value: %.2f M %1.2f N %i S %.3f\" % (\ 864 | \ curval, self.maxval, self.lowcounter, self.sumval ) )\n \ 865 | \ \n if curval > self.maxval:\n self.maxval\ 866 | \ = curval\n \n if curval > self.threshold and\ 867 | \ self.start_state == 0:\n # Signal triggers the threshold\n\ 868 | \ self.start_state = 1\n lowavg = self.sumval\ 869 | \ / self.lowcounter\n #print (\"A,%.2f,%.2f,\" % ( curval,\ 870 | \ time.time() ), end=\"\" )\n print (\"A,%.2f,%.2f,\" % (\ 871 | \ lowavg, time.time() ), end=\"\", file=self.outfile )\n elif\ 872 | \ curval < self.threshold and self.start_state == 1:\n #\ 873 | \ Signal drops below threshold\n #print (\"U,%.2f,%.2f\"\ 874 | \ % ( curval, time.time() ), end=\"\\n\")\n print (\"U,%.2f,%.2f\"\ 875 | \ % ( self.maxval, time.time() ), end=\"\\n\", file=self.outfile, flush=True)\n\ 876 | \ self.start_state = 0\n self.sumval =\ 877 | \ 0\n self.lowcounter = 1\n self.maxval\ 878 | \ = 0 \n else:\n # Signal remains\ 879 | \ under threshold\n #self.sumval += curval\n \ 880 | \ self.sumval += noiseval\n self.lowcounter += 1\n\ 881 | \t\t\t\n \n return len(input_items[0])\n" 882 | affinity: '' 883 | alias: '' 884 | comment: '' 885 | fftsize: fftsize 886 | maxoutbuf: '0' 887 | minoutbuf: '0' 888 | reportfile: outfile 889 | start_state: start_state 890 | threshold: threshold 891 | verbose: verbose 892 | states: 893 | _io_cache: ('Specmon2', 'blk', [('fftsize', '1024'), ('start_state', '0'), ('threshold', 894 | '1.0'), ('verbose', '0'), ('reportfile', "'/tmp/logfile.csv'")], [('0', 'float', 895 | 1024)], [], 'Specmon data analysis block. \n This block is the improved version 896 | for specmon\n ', ['fftsize', 'reportfile', 'start_state', 'threshold', 'verbose']) 897 | bus_sink: false 898 | bus_source: false 899 | bus_structure: null 900 | coordinate: [16, 516.0] 901 | rotation: 180 902 | state: enabled 903 | - name: threshold 904 | id: parameter 905 | parameters: 906 | alias: '' 907 | comment: '' 908 | hide: none 909 | label: Threshold 910 | short_id: T 911 | type: eng_float 912 | value: '.1' 913 | states: 914 | bus_sink: false 915 | bus_source: false 916 | bus_structure: null 917 | coordinate: [752, 32] 918 | rotation: 0 919 | state: enabled 920 | - name: verbose 921 | id: parameter 922 | parameters: 923 | alias: '' 924 | comment: '' 925 | hide: none 926 | label: Print verbose values 927 | short_id: v 928 | type: intx 929 | value: '0' 930 | states: 931 | bus_sink: false 932 | bus_source: false 933 | bus_structure: null 934 | coordinate: [1016, 32] 935 | rotation: 0 936 | state: enabled 937 | 938 | connections: 939 | - [blocks_add_xx_0, '0', specmon_block, '0'] 940 | - [blocks_complex_to_mag_squared_0, '0', blocks_integrate_xx_0, '0'] 941 | - [blocks_file_source_0, '0', blocks_add_xx_0, '1'] 942 | - [blocks_head_0, '0', blocks_moving_average_xx_0, '0'] 943 | - [blocks_head_0, '0', blocks_sub_xx_0, '0'] 944 | - [blocks_integrate_xx_0, '0', blocks_multiply_const_vxx_0, '0'] 945 | - [blocks_moving_average_xx_0, '0', blocks_sub_xx_0, '1'] 946 | - [blocks_multiply_const_vxx_0, '0', blocks_nlog10_ff_0, '0'] 947 | - [blocks_nlog10_ff_0, '0', blocks_add_xx_0, '0'] 948 | - [blocks_nlog10_ff_0, '0', blocks_file_sink_0, '0'] 949 | - [blocks_stream_to_vector_0, '0', fft_vxx_0, '0'] 950 | - [blocks_sub_xx_0, '0', blocks_stream_to_vector_0, '0'] 951 | - [fft_vxx_0, '0', blocks_complex_to_mag_squared_0, '0'] 952 | - [osmosdr_source_0, '0', blocks_head_0, '0'] 953 | 954 | metadata: 955 | file_format: 1 956 | -------------------------------------------------------------------------------- /specmon2_gui.grc: -------------------------------------------------------------------------------- 1 | options: 2 | parameters: 3 | author: PE1RIK 4 | category: '[GRC Hier Blocks]' 5 | cmake_opt: '' 6 | comment: '' 7 | copyright: '' 8 | description: '' 9 | gen_cmake: 'On' 10 | gen_linking: dynamic 11 | generate_options: qt_gui 12 | hier_block_src_path: '.:' 13 | id: specmon2_gui 14 | max_nouts: '0' 15 | output_language: python 16 | placement: (0,0) 17 | qt_qss_theme: '' 18 | realtime_scheduling: '' 19 | run: 'True' 20 | run_command: '{python} -u {filename}' 21 | run_options: run 22 | sizing_mode: fixed 23 | thread_safe_setters: '' 24 | title: '' 25 | window_size: '' 26 | states: 27 | bus_sink: false 28 | bus_source: false 29 | bus_structure: null 30 | coordinate: [8, 8] 31 | rotation: 0 32 | state: enabled 33 | 34 | blocks: 35 | - name: freq 36 | id: variable_qtgui_range 37 | parameters: 38 | comment: '' 39 | gui_hint: '' 40 | label: '' 41 | min_len: '200' 42 | orient: Qt.Horizontal 43 | rangeType: float 44 | start: 70e6 45 | step: 25e3 46 | stop: 1e9 47 | value: 145e6 48 | widget: counter_slider 49 | states: 50 | bus_sink: false 51 | bus_source: false 52 | bus_structure: null 53 | coordinate: [328, 32] 54 | rotation: 0 55 | state: enabled 56 | - name: intcount 57 | id: variable 58 | parameters: 59 | comment: 'Integration count. 60 | 61 | Also used for normalisation' 62 | value: int(samp_rate/(fftsize * 5)) 63 | states: 64 | bus_sink: false 65 | bus_source: false 66 | bus_structure: null 67 | coordinate: [1120, 632] 68 | rotation: 0 69 | state: enabled 70 | - name: rfgain 71 | id: variable_qtgui_range 72 | parameters: 73 | comment: '' 74 | gui_hint: '' 75 | label: '' 76 | min_len: '200' 77 | orient: Qt.Horizontal 78 | rangeType: float 79 | start: '0' 80 | step: '1' 81 | stop: '70' 82 | value: '20' 83 | widget: counter_slider 84 | states: 85 | bus_sink: false 86 | bus_source: false 87 | bus_structure: null 88 | coordinate: [496, 32] 89 | rotation: 0 90 | state: enabled 91 | - name: start_state 92 | id: variable 93 | parameters: 94 | comment: '' 95 | value: '0' 96 | states: 97 | bus_sink: false 98 | bus_source: false 99 | bus_structure: null 100 | coordinate: [880, 632] 101 | rotation: 0 102 | state: enabled 103 | - name: threshold 104 | id: variable_qtgui_range 105 | parameters: 106 | comment: '' 107 | gui_hint: '' 108 | label: '' 109 | min_len: '200' 110 | orient: Qt.Horizontal 111 | rangeType: float 112 | start: '0' 113 | step: '.1' 114 | stop: '50' 115 | value: '10' 116 | widget: counter_slider 117 | states: 118 | bus_sink: false 119 | bus_source: false 120 | bus_structure: null 121 | coordinate: [672, 348.0] 122 | rotation: 0 123 | state: enabled 124 | - name: bbgain 125 | id: parameter 126 | parameters: 127 | alias: '' 128 | comment: '' 129 | hide: none 130 | label: BB-Gain 131 | short_id: b 132 | type: intx 133 | value: '30' 134 | states: 135 | bus_sink: false 136 | bus_source: false 137 | bus_structure: null 138 | coordinate: [632, 32] 139 | rotation: 0 140 | state: enabled 141 | - name: blocks_add_xx_0 142 | id: blocks_add_xx 143 | parameters: 144 | affinity: '' 145 | alias: '' 146 | comment: '' 147 | maxoutbuf: '0' 148 | minoutbuf: '0' 149 | num_inputs: '2' 150 | type: float 151 | vlen: fftsize 152 | states: 153 | bus_sink: false 154 | bus_source: false 155 | bus_structure: null 156 | coordinate: [296, 496] 157 | rotation: 180 158 | state: enabled 159 | - name: blocks_complex_to_mag_squared_0 160 | id: blocks_complex_to_mag_squared 161 | parameters: 162 | affinity: '' 163 | alias: '' 164 | comment: '' 165 | maxoutbuf: '0' 166 | minoutbuf: '0' 167 | vlen: fftsize 168 | states: 169 | bus_sink: false 170 | bus_source: false 171 | bus_structure: null 172 | coordinate: [1088, 504] 173 | rotation: 180 174 | state: enabled 175 | - name: blocks_file_source_0 176 | id: blocks_file_source 177 | parameters: 178 | affinity: '' 179 | alias: '' 180 | begin_tag: pmt.PMT_NIL 181 | comment: '' 182 | file: calibvec 183 | length: '0' 184 | maxoutbuf: '0' 185 | minoutbuf: '0' 186 | offset: '0' 187 | repeat: 'True' 188 | type: float 189 | vlen: fftsize 190 | states: 191 | bus_sink: false 192 | bus_source: false 193 | bus_structure: null 194 | coordinate: [496, 656] 195 | rotation: 180 196 | state: enabled 197 | - name: blocks_head_0 198 | id: blocks_head 199 | parameters: 200 | affinity: '' 201 | alias: '' 202 | comment: '' 203 | maxoutbuf: '0' 204 | minoutbuf: '0' 205 | num_items: int(runtime*samp_rate) 206 | type: complex 207 | vlen: '1' 208 | states: 209 | bus_sink: false 210 | bus_source: false 211 | bus_structure: null 212 | coordinate: [272, 232] 213 | rotation: 0 214 | state: enabled 215 | - name: blocks_integrate_xx_0 216 | id: blocks_integrate_xx 217 | parameters: 218 | affinity: '' 219 | alias: '' 220 | comment: '' 221 | decim: intcount 222 | maxoutbuf: '0' 223 | minoutbuf: '0' 224 | type: float 225 | vlen: fftsize 226 | states: 227 | bus_sink: false 228 | bus_source: false 229 | bus_structure: null 230 | coordinate: [896, 496] 231 | rotation: 180 232 | state: enabled 233 | - name: blocks_moving_average_xx_0 234 | id: blocks_moving_average_xx 235 | parameters: 236 | affinity: '' 237 | alias: '' 238 | comment: '' 239 | length: '500' 240 | max_iter: '4000' 241 | maxoutbuf: '0' 242 | minoutbuf: '0' 243 | scale: 1.0/500 244 | type: complex 245 | vlen: '1' 246 | states: 247 | bus_sink: false 248 | bus_source: false 249 | bus_structure: null 250 | coordinate: [480, 280] 251 | rotation: 0 252 | state: enabled 253 | - name: blocks_multiply_const_vxx_0 254 | id: blocks_multiply_const_vxx 255 | parameters: 256 | affinity: '' 257 | alias: '' 258 | comment: Normalize integrated vectors 259 | const: '[1.0/intcount]*fftsize' 260 | maxoutbuf: '0' 261 | minoutbuf: '0' 262 | type: float 263 | vlen: fftsize 264 | states: 265 | bus_sink: false 266 | bus_source: false 267 | bus_structure: null 268 | coordinate: [664, 496] 269 | rotation: 180 270 | state: enabled 271 | - name: blocks_nlog10_ff_0 272 | id: blocks_nlog10_ff 273 | parameters: 274 | affinity: '' 275 | alias: '' 276 | comment: '' 277 | k: '0' 278 | maxoutbuf: '0' 279 | minoutbuf: '0' 280 | n: '10' 281 | vlen: fftsize 282 | states: 283 | bus_sink: false 284 | bus_source: false 285 | bus_structure: null 286 | coordinate: [488, 488] 287 | rotation: 180 288 | state: enabled 289 | - name: blocks_stream_to_vector_0 290 | id: blocks_stream_to_vector 291 | parameters: 292 | affinity: '' 293 | alias: '' 294 | comment: '' 295 | maxoutbuf: '0' 296 | minoutbuf: '0' 297 | num_items: fftsize 298 | type: complex 299 | vlen: '1' 300 | states: 301 | bus_sink: false 302 | bus_source: false 303 | bus_structure: null 304 | coordinate: [848, 248] 305 | rotation: 0 306 | state: enabled 307 | - name: blocks_sub_xx_0 308 | id: blocks_sub_xx 309 | parameters: 310 | affinity: '' 311 | alias: '' 312 | comment: '' 313 | maxoutbuf: '0' 314 | minoutbuf: '0' 315 | num_inputs: '2' 316 | type: complex 317 | vlen: '1' 318 | states: 319 | bus_sink: false 320 | bus_source: false 321 | bus_structure: null 322 | coordinate: [680, 224] 323 | rotation: 0 324 | state: enabled 325 | - name: blocks_vector_source_x_0 326 | id: blocks_vector_source_x 327 | parameters: 328 | affinity: '' 329 | alias: '' 330 | comment: '' 331 | maxoutbuf: '0' 332 | minoutbuf: '0' 333 | repeat: 'True' 334 | tags: '[]' 335 | type: float 336 | vector: '[threshold]*fftsize' 337 | vlen: fftsize 338 | states: 339 | bus_sink: false 340 | bus_source: false 341 | bus_structure: null 342 | coordinate: [296, 648] 343 | rotation: 180 344 | state: enabled 345 | - name: calibvec 346 | id: parameter 347 | parameters: 348 | alias: '' 349 | comment: '' 350 | hide: none 351 | label: Calibration Vector 352 | short_id: c 353 | type: str 354 | value: /home/bart/grc/210926-zero-2048.vec 355 | states: 356 | bus_sink: false 357 | bus_source: false 358 | bus_structure: null 359 | coordinate: [664, 640] 360 | rotation: 0 361 | state: enabled 362 | - name: deviceid 363 | id: parameter 364 | parameters: 365 | alias: '' 366 | comment: '' 367 | hide: none 368 | label: Device ID 369 | short_id: d 370 | type: str 371 | value: rtl=0 372 | states: 373 | bus_sink: false 374 | bus_source: false 375 | bus_structure: null 376 | coordinate: [200, 32.0] 377 | rotation: 0 378 | state: enabled 379 | - name: fft_vxx_0 380 | id: fft_vxx 381 | parameters: 382 | affinity: '' 383 | alias: '' 384 | comment: '' 385 | fft_size: fftsize 386 | forward: 'True' 387 | maxoutbuf: '0' 388 | minoutbuf: '0' 389 | nthreads: '1' 390 | shift: 'True' 391 | type: complex 392 | window: window.blackmanharris(fftsize) 393 | states: 394 | bus_sink: false 395 | bus_source: false 396 | bus_structure: null 397 | coordinate: [1056, 216] 398 | rotation: 0 399 | state: enabled 400 | - name: fftsize 401 | id: parameter 402 | parameters: 403 | alias: '' 404 | comment: '' 405 | hide: none 406 | label: FFT size 407 | short_id: F 408 | type: intx 409 | value: '1024' 410 | states: 411 | bus_sink: false 412 | bus_source: false 413 | bus_structure: null 414 | coordinate: [880, 736] 415 | rotation: 0 416 | state: enabled 417 | - name: osmosdr_source_0 418 | id: osmosdr_source 419 | parameters: 420 | affinity: '' 421 | alias: '' 422 | ant0: '' 423 | ant1: '' 424 | ant10: '' 425 | ant11: '' 426 | ant12: '' 427 | ant13: '' 428 | ant14: '' 429 | ant15: '' 430 | ant16: '' 431 | ant17: '' 432 | ant18: '' 433 | ant19: '' 434 | ant2: '' 435 | ant20: '' 436 | ant21: '' 437 | ant22: '' 438 | ant23: '' 439 | ant24: '' 440 | ant25: '' 441 | ant26: '' 442 | ant27: '' 443 | ant28: '' 444 | ant29: '' 445 | ant3: '' 446 | ant30: '' 447 | ant31: '' 448 | ant4: '' 449 | ant5: '' 450 | ant6: '' 451 | ant7: '' 452 | ant8: '' 453 | ant9: '' 454 | args: deviceid 455 | bb_gain0: bbgain 456 | bb_gain1: '20' 457 | bb_gain10: '20' 458 | bb_gain11: '20' 459 | bb_gain12: '20' 460 | bb_gain13: '20' 461 | bb_gain14: '20' 462 | bb_gain15: '20' 463 | bb_gain16: '20' 464 | bb_gain17: '20' 465 | bb_gain18: '20' 466 | bb_gain19: '20' 467 | bb_gain2: '20' 468 | bb_gain20: '20' 469 | bb_gain21: '20' 470 | bb_gain22: '20' 471 | bb_gain23: '20' 472 | bb_gain24: '20' 473 | bb_gain25: '20' 474 | bb_gain26: '20' 475 | bb_gain27: '20' 476 | bb_gain28: '20' 477 | bb_gain29: '20' 478 | bb_gain3: '20' 479 | bb_gain30: '20' 480 | bb_gain31: '20' 481 | bb_gain4: '20' 482 | bb_gain5: '20' 483 | bb_gain6: '20' 484 | bb_gain7: '20' 485 | bb_gain8: '20' 486 | bb_gain9: '20' 487 | bw0: '0' 488 | bw1: '0' 489 | bw10: '0' 490 | bw11: '0' 491 | bw12: '0' 492 | bw13: '0' 493 | bw14: '0' 494 | bw15: '0' 495 | bw16: '0' 496 | bw17: '0' 497 | bw18: '0' 498 | bw19: '0' 499 | bw2: '0' 500 | bw20: '0' 501 | bw21: '0' 502 | bw22: '0' 503 | bw23: '0' 504 | bw24: '0' 505 | bw25: '0' 506 | bw26: '0' 507 | bw27: '0' 508 | bw28: '0' 509 | bw29: '0' 510 | bw3: '0' 511 | bw30: '0' 512 | bw31: '0' 513 | bw4: '0' 514 | bw5: '0' 515 | bw6: '0' 516 | bw7: '0' 517 | bw8: '0' 518 | bw9: '0' 519 | clock_source0: '' 520 | clock_source1: '' 521 | clock_source2: '' 522 | clock_source3: '' 523 | clock_source4: '' 524 | clock_source5: '' 525 | clock_source6: '' 526 | clock_source7: '' 527 | comment: '' 528 | corr0: '0' 529 | corr1: '0' 530 | corr10: '0' 531 | corr11: '0' 532 | corr12: '0' 533 | corr13: '0' 534 | corr14: '0' 535 | corr15: '0' 536 | corr16: '0' 537 | corr17: '0' 538 | corr18: '0' 539 | corr19: '0' 540 | corr2: '0' 541 | corr20: '0' 542 | corr21: '0' 543 | corr22: '0' 544 | corr23: '0' 545 | corr24: '0' 546 | corr25: '0' 547 | corr26: '0' 548 | corr27: '0' 549 | corr28: '0' 550 | corr29: '0' 551 | corr3: '0' 552 | corr30: '0' 553 | corr31: '0' 554 | corr4: '0' 555 | corr5: '0' 556 | corr6: '0' 557 | corr7: '0' 558 | corr8: '0' 559 | corr9: '0' 560 | dc_offset_mode0: '0' 561 | dc_offset_mode1: '0' 562 | dc_offset_mode10: '0' 563 | dc_offset_mode11: '0' 564 | dc_offset_mode12: '0' 565 | dc_offset_mode13: '0' 566 | dc_offset_mode14: '0' 567 | dc_offset_mode15: '0' 568 | dc_offset_mode16: '0' 569 | dc_offset_mode17: '0' 570 | dc_offset_mode18: '0' 571 | dc_offset_mode19: '0' 572 | dc_offset_mode2: '0' 573 | dc_offset_mode20: '0' 574 | dc_offset_mode21: '0' 575 | dc_offset_mode22: '0' 576 | dc_offset_mode23: '0' 577 | dc_offset_mode24: '0' 578 | dc_offset_mode25: '0' 579 | dc_offset_mode26: '0' 580 | dc_offset_mode27: '0' 581 | dc_offset_mode28: '0' 582 | dc_offset_mode29: '0' 583 | dc_offset_mode3: '0' 584 | dc_offset_mode30: '0' 585 | dc_offset_mode31: '0' 586 | dc_offset_mode4: '0' 587 | dc_offset_mode5: '0' 588 | dc_offset_mode6: '0' 589 | dc_offset_mode7: '0' 590 | dc_offset_mode8: '0' 591 | dc_offset_mode9: '0' 592 | freq0: freq 593 | freq1: 100e6 594 | freq10: 100e6 595 | freq11: 100e6 596 | freq12: 100e6 597 | freq13: 100e6 598 | freq14: 100e6 599 | freq15: 100e6 600 | freq16: 100e6 601 | freq17: 100e6 602 | freq18: 100e6 603 | freq19: 100e6 604 | freq2: 100e6 605 | freq20: 100e6 606 | freq21: 100e6 607 | freq22: 100e6 608 | freq23: 100e6 609 | freq24: 100e6 610 | freq25: 100e6 611 | freq26: 100e6 612 | freq27: 100e6 613 | freq28: 100e6 614 | freq29: 100e6 615 | freq3: 100e6 616 | freq30: 100e6 617 | freq31: 100e6 618 | freq4: 100e6 619 | freq5: 100e6 620 | freq6: 100e6 621 | freq7: 100e6 622 | freq8: 100e6 623 | freq9: 100e6 624 | gain0: rfgain 625 | gain1: '10' 626 | gain10: '10' 627 | gain11: '10' 628 | gain12: '10' 629 | gain13: '10' 630 | gain14: '10' 631 | gain15: '10' 632 | gain16: '10' 633 | gain17: '10' 634 | gain18: '10' 635 | gain19: '10' 636 | gain2: '10' 637 | gain20: '10' 638 | gain21: '10' 639 | gain22: '10' 640 | gain23: '10' 641 | gain24: '10' 642 | gain25: '10' 643 | gain26: '10' 644 | gain27: '10' 645 | gain28: '10' 646 | gain29: '10' 647 | gain3: '10' 648 | gain30: '10' 649 | gain31: '10' 650 | gain4: '10' 651 | gain5: '10' 652 | gain6: '10' 653 | gain7: '10' 654 | gain8: '10' 655 | gain9: '10' 656 | gain_mode0: 'False' 657 | gain_mode1: 'False' 658 | gain_mode10: 'False' 659 | gain_mode11: 'False' 660 | gain_mode12: 'False' 661 | gain_mode13: 'False' 662 | gain_mode14: 'False' 663 | gain_mode15: 'False' 664 | gain_mode16: 'False' 665 | gain_mode17: 'False' 666 | gain_mode18: 'False' 667 | gain_mode19: 'False' 668 | gain_mode2: 'False' 669 | gain_mode20: 'False' 670 | gain_mode21: 'False' 671 | gain_mode22: 'False' 672 | gain_mode23: 'False' 673 | gain_mode24: 'False' 674 | gain_mode25: 'False' 675 | gain_mode26: 'False' 676 | gain_mode27: 'False' 677 | gain_mode28: 'False' 678 | gain_mode29: 'False' 679 | gain_mode3: 'False' 680 | gain_mode30: 'False' 681 | gain_mode31: 'False' 682 | gain_mode4: 'False' 683 | gain_mode5: 'False' 684 | gain_mode6: 'False' 685 | gain_mode7: 'False' 686 | gain_mode8: 'False' 687 | gain_mode9: 'False' 688 | if_gain0: '20' 689 | if_gain1: '20' 690 | if_gain10: '20' 691 | if_gain11: '20' 692 | if_gain12: '20' 693 | if_gain13: '20' 694 | if_gain14: '20' 695 | if_gain15: '20' 696 | if_gain16: '20' 697 | if_gain17: '20' 698 | if_gain18: '20' 699 | if_gain19: '20' 700 | if_gain2: '20' 701 | if_gain20: '20' 702 | if_gain21: '20' 703 | if_gain22: '20' 704 | if_gain23: '20' 705 | if_gain24: '20' 706 | if_gain25: '20' 707 | if_gain26: '20' 708 | if_gain27: '20' 709 | if_gain28: '20' 710 | if_gain29: '20' 711 | if_gain3: '20' 712 | if_gain30: '20' 713 | if_gain31: '20' 714 | if_gain4: '20' 715 | if_gain5: '20' 716 | if_gain6: '20' 717 | if_gain7: '20' 718 | if_gain8: '20' 719 | if_gain9: '20' 720 | iq_balance_mode0: '0' 721 | iq_balance_mode1: '0' 722 | iq_balance_mode10: '0' 723 | iq_balance_mode11: '0' 724 | iq_balance_mode12: '0' 725 | iq_balance_mode13: '0' 726 | iq_balance_mode14: '0' 727 | iq_balance_mode15: '0' 728 | iq_balance_mode16: '0' 729 | iq_balance_mode17: '0' 730 | iq_balance_mode18: '0' 731 | iq_balance_mode19: '0' 732 | iq_balance_mode2: '0' 733 | iq_balance_mode20: '0' 734 | iq_balance_mode21: '0' 735 | iq_balance_mode22: '0' 736 | iq_balance_mode23: '0' 737 | iq_balance_mode24: '0' 738 | iq_balance_mode25: '0' 739 | iq_balance_mode26: '0' 740 | iq_balance_mode27: '0' 741 | iq_balance_mode28: '0' 742 | iq_balance_mode29: '0' 743 | iq_balance_mode3: '0' 744 | iq_balance_mode30: '0' 745 | iq_balance_mode31: '0' 746 | iq_balance_mode4: '0' 747 | iq_balance_mode5: '0' 748 | iq_balance_mode6: '0' 749 | iq_balance_mode7: '0' 750 | iq_balance_mode8: '0' 751 | iq_balance_mode9: '0' 752 | maxoutbuf: '0' 753 | minoutbuf: '0' 754 | nchan: '1' 755 | num_mboards: '1' 756 | sample_rate: samp_rate 757 | sync: sync 758 | time_source0: '' 759 | time_source1: '' 760 | time_source2: '' 761 | time_source3: '' 762 | time_source4: '' 763 | time_source5: '' 764 | time_source6: '' 765 | time_source7: '' 766 | type: fc32 767 | states: 768 | bus_sink: false 769 | bus_source: false 770 | bus_structure: null 771 | coordinate: [8, 212] 772 | rotation: 0 773 | state: enabled 774 | - name: outfile 775 | id: parameter 776 | parameters: 777 | alias: '' 778 | comment: '' 779 | hide: none 780 | label: Output File 781 | short_id: O 782 | type: str 783 | value: '"/tmp/logfile.csv"' 784 | states: 785 | bus_sink: false 786 | bus_source: false 787 | bus_structure: null 788 | coordinate: [1224, 32.0] 789 | rotation: 0 790 | state: true 791 | - name: qtgui_freq_sink_x_0 792 | id: qtgui_freq_sink_x 793 | parameters: 794 | affinity: '' 795 | alias: '' 796 | alpha1: '1.0' 797 | alpha10: '1.0' 798 | alpha2: '1.0' 799 | alpha3: '1.0' 800 | alpha4: '1.0' 801 | alpha5: '1.0' 802 | alpha6: '1.0' 803 | alpha7: '1.0' 804 | alpha8: '1.0' 805 | alpha9: '1.0' 806 | autoscale: 'False' 807 | average: '1.0' 808 | axislabels: 'True' 809 | bw: samp_rate 810 | color1: '"blue"' 811 | color10: '"dark blue"' 812 | color2: '"red"' 813 | color3: '"green"' 814 | color4: '"black"' 815 | color5: '"cyan"' 816 | color6: '"magenta"' 817 | color7: '"yellow"' 818 | color8: '"dark red"' 819 | color9: '"dark green"' 820 | comment: '' 821 | ctrlpanel: 'True' 822 | fc: freq 823 | fftsize: fftsize 824 | freqhalf: 'True' 825 | grid: 'True' 826 | gui_hint: tab0@0 827 | label: Relative Gain 828 | label1: '' 829 | label10: '' 830 | label2: '' 831 | label3: '' 832 | label4: '' 833 | label5: '' 834 | label6: '' 835 | label7: '' 836 | label8: '' 837 | label9: '' 838 | legend: 'True' 839 | maxoutbuf: '0' 840 | minoutbuf: '0' 841 | name: '""' 842 | nconnections: '1' 843 | showports: 'True' 844 | tr_chan: '0' 845 | tr_level: '0.0' 846 | tr_mode: qtgui.TRIG_MODE_FREE 847 | tr_tag: '""' 848 | type: complex 849 | units: dB 850 | update_time: '0.10' 851 | width1: '1' 852 | width10: '1' 853 | width2: '1' 854 | width3: '1' 855 | width4: '1' 856 | width5: '1' 857 | width6: '1' 858 | width7: '1' 859 | width8: '1' 860 | width9: '1' 861 | wintype: firdes.WIN_BLACKMAN_hARRIS 862 | ymax: '10' 863 | ymin: '-140' 864 | states: 865 | bus_sink: false 866 | bus_source: false 867 | bus_structure: null 868 | coordinate: [864, 360] 869 | rotation: 0 870 | state: enabled 871 | - name: qtgui_vector_sink_f_0 872 | id: qtgui_vector_sink_f 873 | parameters: 874 | affinity: '' 875 | alias: '' 876 | alpha1: '1.0' 877 | alpha10: '1.0' 878 | alpha2: '1.0' 879 | alpha3: '1.0' 880 | alpha4: '1.0' 881 | alpha5: '1.0' 882 | alpha6: '1.0' 883 | alpha7: '1.0' 884 | alpha8: '1.0' 885 | alpha9: '1.0' 886 | autoscale: 'True' 887 | average: '1.0' 888 | color1: '"blue"' 889 | color10: '"dark blue"' 890 | color2: '"red"' 891 | color3: '"green"' 892 | color4: '"black"' 893 | color5: '"cyan"' 894 | color6: '"magenta"' 895 | color7: '"yellow"' 896 | color8: '"dark red"' 897 | color9: '"dark green"' 898 | comment: '' 899 | grid: 'True' 900 | gui_hint: tab0@1 901 | label1: '' 902 | label10: '' 903 | label2: '' 904 | label3: '' 905 | label4: '' 906 | label5: '' 907 | label6: '' 908 | label7: '' 909 | label8: '' 910 | label9: '' 911 | maxoutbuf: '0' 912 | minoutbuf: '0' 913 | name: '""' 914 | nconnections: '2' 915 | ref_level: '0' 916 | showports: 'True' 917 | update_time: '0.10' 918 | vlen: fftsize 919 | width1: '1' 920 | width10: '1' 921 | width2: '1' 922 | width3: '1' 923 | width4: '1' 924 | width5: '1' 925 | width6: '1' 926 | width7: '1' 927 | width8: '1' 928 | width9: '1' 929 | x_axis_label: '"x-Axis"' 930 | x_start: freq-(samp_rate/2) 931 | x_step: samp_rate/fftsize 932 | x_units: '""' 933 | y_axis_label: '"y-Axis"' 934 | y_units: '""' 935 | ymax: '10' 936 | ymin: '-140' 937 | states: 938 | bus_sink: false 939 | bus_source: false 940 | bus_structure: null 941 | coordinate: [16, 636] 942 | rotation: 180 943 | state: enabled 944 | - name: runtime 945 | id: parameter 946 | parameters: 947 | alias: '' 948 | comment: '' 949 | hide: none 950 | label: '' 951 | short_id: R 952 | type: intx 953 | value: '3590' 954 | states: 955 | bus_sink: false 956 | bus_source: false 957 | bus_structure: null 958 | coordinate: [1120, 40.0] 959 | rotation: 0 960 | state: enabled 961 | - name: samp_rate 962 | id: parameter 963 | parameters: 964 | alias: '' 965 | comment: '' 966 | hide: none 967 | label: Sample Rate 968 | short_id: s 969 | type: eng_float 970 | value: 2e6 971 | states: 972 | bus_sink: false 973 | bus_source: false 974 | bus_structure: null 975 | coordinate: [760, 32] 976 | rotation: 0 977 | state: enabled 978 | - name: specmon_block 979 | id: epy_block 980 | parameters: 981 | _source_code: "\"\"\"\nEmbedded Python Blocks:\n\nEach time this file is saved,\ 982 | \ GRC will instantiate the first class it finds\nto get ports and parameters\ 983 | \ of your block. The arguments to __init__ will\nbe the parameters. All of\ 984 | \ them are required to have default values!\n\"\"\"\n\n#from __future__ import\ 985 | \ print_function\nimport numpy as np\nfrom gnuradio import gr\nimport time\n\ 986 | \n\nclass blk(gr.sync_block): # other base classes are basic_block, decim_block,\ 987 | \ interp_block\n \"\"\"Specmon data analysis block. \n This block is the\ 988 | \ improved version for specmon\n \"\"\"\n\n\t# Don't use \"logfile\" as varname\ 989 | \ as it's reserved in GRC\n def __init__(self, fftsize=1024, start_state=0,\ 990 | \ threshold=1.0, verbose=0, reportfile=\"/tmp/logfile.csv\"): # only default\ 991 | \ arguments here\n \"\"\"arguments to this function show up as parameters\ 992 | \ in GRC\"\"\"\n self.fftsize = fftsize\n self.start_state = start_state\n\ 993 | \ self.threshold = threshold\n self.verbose = verbose\n \ 994 | \ self.maxval = 0\n self.sumval = 0\n self.lowcounter = 1\n \ 995 | \ self.reportfile = reportfile\n gr.sync_block.__init__(\n \ 996 | \ self,\n name='Specmon2', # will show up in GRC\n \ 997 | \ in_sig=[(np.float32,self.fftsize)],\n out_sig=None\n \ 998 | \ )\n # Print startline\n self.outfile = open(reportfile, \"\ 999 | a\")\n print (\"S,%.2f,H,%s,T,%.2f\" % ( time.time(), str(time.strftime(\"\ 1000 | %H\")), threshold ), file=self.outfile, flush=True )\n \n def work(self,\ 1001 | \ input_items, output_items):\n speclist = np.array(input_items[0][0])\n\ 1002 | \ # Peak for max-value\n curval = np.amax(speclist)\n #\ 1003 | \ Median for median noise level\n noiseval = np.median(speclist)\n \ 1004 | \ if self.verbose == 1:\n #print (\"%.2f\" % curval)\n \ 1005 | \ print (\"Current value: %.2f M %1.2f N %i S %.3f\" % ( curval, self.maxval,\ 1006 | \ self.lowcounter, self.sumval ) )\n \n if curval > self.maxval:\n\ 1007 | \ self.maxval = curval\n \n if curval > self.threshold\ 1008 | \ and self.start_state == 0:\n # Signal triggers the threshold\n\ 1009 | \ self.start_state = 1\n lowavg = self.sumval / self.lowcounter\n\ 1010 | \ #print (\"A,%.2f,%.2f,\" % ( curval, time.time() ), end=\"\" )\n\ 1011 | \ print (\"A,%.2f,%.2f,\" % ( lowavg, time.time() ), end=\"\", file=self.outfile\ 1012 | \ )\n elif curval < self.threshold and self.start_state == 1:\n \ 1013 | \ # Signal drops below threshold\n #print (\"U,%.2f,%.2f\"\ 1014 | \ % ( curval, time.time() ), end=\"\\n\")\n print (\"U,%.2f,%.2f\"\ 1015 | \ % ( self.maxval, time.time() ), end=\"\\n\", file=self.outfile, flush=True)\n\ 1016 | \ self.start_state = 0\n self.sumval = 0\n \ 1017 | \ self.lowcounter = 1\n self.maxval = 0 \n else:\n\ 1018 | \ # Signal remains under threshold\n #self.sumval += curval\n\ 1019 | \ self.sumval += noiseval\n self.lowcounter += 1\n\t\t\ 1020 | \t\n \n return len(input_items[0])\n" 1021 | affinity: '' 1022 | alias: '' 1023 | comment: '' 1024 | fftsize: fftsize 1025 | maxoutbuf: '0' 1026 | minoutbuf: '0' 1027 | reportfile: outfile 1028 | start_state: start_state 1029 | threshold: threshold 1030 | verbose: verbose 1031 | states: 1032 | _io_cache: ('Specmon2', 'blk', [('fftsize', '1024'), ('start_state', '0'), ('threshold', 1033 | '1.0'), ('verbose', '0'), ('reportfile', "'/tmp/logfile.csv'")], [('0', 'float', 1034 | 1024)], [], 'Specmon data analysis block. \n This block is the improved version 1035 | for specmon\n ', ['fftsize', 'reportfile', 'start_state', 'threshold', 'verbose']) 1036 | bus_sink: false 1037 | bus_source: false 1038 | bus_structure: null 1039 | coordinate: [40, 472.0] 1040 | rotation: 180 1041 | state: enabled 1042 | - name: tab0 1043 | id: qtgui_tab_widget 1044 | parameters: 1045 | alias: '' 1046 | comment: '' 1047 | gui_hint: '' 1048 | label0: freq sink 1049 | label1: vector sink 1050 | label10: Tab 10 1051 | label11: Tab 11 1052 | label12: Tab 12 1053 | label13: Tab 13 1054 | label14: Tab 14 1055 | label15: Tab 15 1056 | label16: Tab 16 1057 | label17: Tab 17 1058 | label18: Tab 18 1059 | label19: Tab 19 1060 | label2: Tab 2 1061 | label3: Tab 3 1062 | label4: Tab 4 1063 | label5: Tab 5 1064 | label6: Tab 6 1065 | label7: Tab 7 1066 | label8: Tab 8 1067 | label9: Tab 9 1068 | num_tabs: '2' 1069 | states: 1070 | bus_sink: false 1071 | bus_source: false 1072 | bus_structure: null 1073 | coordinate: [296, 336.0] 1074 | rotation: 0 1075 | state: enabled 1076 | - name: verbose 1077 | id: parameter 1078 | parameters: 1079 | alias: '' 1080 | comment: '' 1081 | hide: none 1082 | label: Print verbose values 1083 | short_id: v 1084 | type: intx 1085 | value: '0' 1086 | states: 1087 | bus_sink: false 1088 | bus_source: false 1089 | bus_structure: null 1090 | coordinate: [912, 32] 1091 | rotation: 0 1092 | state: enabled 1093 | 1094 | connections: 1095 | - [blocks_add_xx_0, '0', qtgui_vector_sink_f_0, '0'] 1096 | - [blocks_add_xx_0, '0', specmon_block, '0'] 1097 | - [blocks_complex_to_mag_squared_0, '0', blocks_integrate_xx_0, '0'] 1098 | - [blocks_file_source_0, '0', blocks_add_xx_0, '1'] 1099 | - [blocks_head_0, '0', blocks_moving_average_xx_0, '0'] 1100 | - [blocks_head_0, '0', blocks_sub_xx_0, '0'] 1101 | - [blocks_integrate_xx_0, '0', blocks_multiply_const_vxx_0, '0'] 1102 | - [blocks_moving_average_xx_0, '0', blocks_sub_xx_0, '1'] 1103 | - [blocks_multiply_const_vxx_0, '0', blocks_nlog10_ff_0, '0'] 1104 | - [blocks_nlog10_ff_0, '0', blocks_add_xx_0, '0'] 1105 | - [blocks_stream_to_vector_0, '0', fft_vxx_0, '0'] 1106 | - [blocks_sub_xx_0, '0', blocks_stream_to_vector_0, '0'] 1107 | - [blocks_sub_xx_0, '0', qtgui_freq_sink_x_0, '0'] 1108 | - [blocks_vector_source_x_0, '0', qtgui_vector_sink_f_0, '1'] 1109 | - [fft_vxx_0, '0', blocks_complex_to_mag_squared_0, '0'] 1110 | - [osmosdr_source_0, '0', blocks_head_0, '0'] 1111 | 1112 | metadata: 1113 | file_format: 1 1114 | -------------------------------------------------------------------------------- /specmon2_replay.grc: -------------------------------------------------------------------------------- 1 | options: 2 | parameters: 3 | author: PE1RIK 4 | category: '[GRC Hier Blocks]' 5 | cmake_opt: '' 6 | comment: '' 7 | copyright: '' 8 | description: '' 9 | gen_cmake: 'On' 10 | gen_linking: dynamic 11 | generate_options: qt_gui 12 | hier_block_src_path: '.:' 13 | id: specmon2_replay 14 | max_nouts: '0' 15 | output_language: python 16 | placement: (0,0) 17 | qt_qss_theme: '' 18 | realtime_scheduling: '' 19 | run: 'True' 20 | run_command: '{python} -u {filename}' 21 | run_options: prompt 22 | sizing_mode: fixed 23 | thread_safe_setters: '' 24 | title: '' 25 | window_size: '' 26 | states: 27 | bus_sink: false 28 | bus_source: false 29 | bus_structure: null 30 | coordinate: [8, 8] 31 | rotation: 0 32 | state: enabled 33 | 34 | blocks: 35 | - name: fftsize 36 | id: variable 37 | parameters: 38 | comment: '' 39 | value: '2048' 40 | states: 41 | bus_sink: false 42 | bus_source: false 43 | bus_structure: null 44 | coordinate: [280, 40] 45 | rotation: 0 46 | state: enabled 47 | - name: freq 48 | id: variable 49 | parameters: 50 | comment: '' 51 | value: 145e6 52 | states: 53 | bus_sink: false 54 | bus_source: false 55 | bus_structure: null 56 | coordinate: [528, 40] 57 | rotation: 0 58 | state: enabled 59 | - name: samp_rate 60 | id: variable 61 | parameters: 62 | comment: '' 63 | value: 2e6 64 | states: 65 | bus_sink: false 66 | bus_source: false 67 | bus_structure: null 68 | coordinate: [408, 40] 69 | rotation: 0 70 | state: enabled 71 | - name: threshold 72 | id: variable_qtgui_range 73 | parameters: 74 | comment: '' 75 | gui_hint: '' 76 | label: '' 77 | min_len: '200' 78 | orient: Qt.Horizontal 79 | rangeType: float 80 | start: '0' 81 | step: '.1' 82 | stop: '20' 83 | value: '8.0' 84 | widget: counter_slider 85 | states: 86 | bus_sink: false 87 | bus_source: false 88 | bus_structure: null 89 | coordinate: [672, 48] 90 | rotation: 0 91 | state: enabled 92 | - name: trate 93 | id: variable_config 94 | parameters: 95 | comment: '' 96 | config_file: /tmp/test.conf 97 | option: trate 98 | section: main 99 | type: int 100 | value: '1' 101 | writeback: None 102 | states: 103 | bus_sink: false 104 | bus_source: false 105 | bus_structure: null 106 | coordinate: [64, 444] 107 | rotation: 0 108 | state: enabled 109 | - name: blocks_add_xx_0 110 | id: blocks_add_xx 111 | parameters: 112 | affinity: '' 113 | alias: '' 114 | comment: '' 115 | maxoutbuf: '0' 116 | minoutbuf: '0' 117 | num_inputs: '2' 118 | type: float 119 | vlen: fftsize 120 | states: 121 | bus_sink: false 122 | bus_source: false 123 | bus_structure: null 124 | coordinate: [736, 336] 125 | rotation: 0 126 | state: enabled 127 | - name: blocks_file_source_0 128 | id: blocks_file_source 129 | parameters: 130 | affinity: '' 131 | alias: '' 132 | begin_tag: pmt.PMT_NIL 133 | comment: Vector source from filesink of specmon2 134 | file: /tmp/210928-1510-145000000-2000000-2048.pvector 135 | length: '0' 136 | maxoutbuf: '0' 137 | minoutbuf: '0' 138 | offset: '0' 139 | repeat: 'False' 140 | type: float 141 | vlen: fftsize 142 | states: 143 | bus_sink: false 144 | bus_source: false 145 | bus_structure: null 146 | coordinate: [176, 200] 147 | rotation: 0 148 | state: enabled 149 | - name: blocks_file_source_1 150 | id: blocks_file_source 151 | parameters: 152 | affinity: '' 153 | alias: '' 154 | begin_tag: pmt.PMT_NIL 155 | comment: '' 156 | file: /home/bart/grc/210928-145M-2e6-20g-2048-0.cal 157 | length: '0' 158 | maxoutbuf: '0' 159 | minoutbuf: '0' 160 | offset: '0' 161 | repeat: 'True' 162 | type: float 163 | vlen: fftsize 164 | states: 165 | bus_sink: false 166 | bus_source: false 167 | bus_structure: null 168 | coordinate: [408, 408] 169 | rotation: 0 170 | state: enabled 171 | - name: blocks_throttle_0 172 | id: blocks_throttle 173 | parameters: 174 | affinity: '' 175 | alias: '' 176 | comment: '' 177 | ignoretag: 'True' 178 | maxoutbuf: '0' 179 | minoutbuf: '0' 180 | samples_per_second: trate 181 | type: float 182 | vlen: fftsize 183 | states: 184 | bus_sink: false 185 | bus_source: false 186 | bus_structure: null 187 | coordinate: [424, 216] 188 | rotation: 0 189 | state: enabled 190 | - name: blocks_vector_source_x_0 191 | id: blocks_vector_source_x 192 | parameters: 193 | affinity: '' 194 | alias: '' 195 | comment: '' 196 | maxoutbuf: '0' 197 | minoutbuf: '0' 198 | repeat: 'True' 199 | tags: '[]' 200 | type: float 201 | vector: '[threshold]*fftsize' 202 | vlen: fftsize 203 | states: 204 | bus_sink: false 205 | bus_source: false 206 | bus_structure: null 207 | coordinate: [1048, 440] 208 | rotation: 180 209 | state: enabled 210 | - name: note_0 211 | id: note 212 | parameters: 213 | alias: '' 214 | comment: 'content of configfile /tmp/test.conf: 215 | 216 | 217 | [main] 218 | 219 | trate = 100' 220 | note: Reminders 221 | states: 222 | bus_sink: false 223 | bus_source: false 224 | bus_structure: null 225 | coordinate: [72, 616] 226 | rotation: 0 227 | state: enabled 228 | - name: qtgui_vector_sink_f_0 229 | id: qtgui_vector_sink_f 230 | parameters: 231 | affinity: '' 232 | alias: '' 233 | alpha1: '1.0' 234 | alpha10: '1.0' 235 | alpha2: '1.0' 236 | alpha3: '1.0' 237 | alpha4: '1.0' 238 | alpha5: '1.0' 239 | alpha6: '1.0' 240 | alpha7: '1.0' 241 | alpha8: '1.0' 242 | alpha9: '1.0' 243 | autoscale: 'False' 244 | average: '1.0' 245 | color1: '"blue"' 246 | color10: '"dark blue"' 247 | color2: '"red"' 248 | color3: '"green"' 249 | color4: '"black"' 250 | color5: '"cyan"' 251 | color6: '"magenta"' 252 | color7: '"yellow"' 253 | color8: '"dark red"' 254 | color9: '"dark green"' 255 | comment: 'X-start: freq-(samp_rate/2) 256 | 257 | X-step: samp_rate/fftsize' 258 | grid: 'True' 259 | gui_hint: '' 260 | label1: '' 261 | label10: '' 262 | label2: '' 263 | label3: '' 264 | label4: '' 265 | label5: '' 266 | label6: '' 267 | label7: '' 268 | label8: '' 269 | label9: '' 270 | maxoutbuf: '0' 271 | minoutbuf: '0' 272 | name: '""' 273 | nconnections: '3' 274 | ref_level: '0' 275 | showports: 'True' 276 | update_time: '0.10' 277 | vlen: fftsize 278 | width1: '1' 279 | width10: '1' 280 | width2: '1' 281 | width3: '1' 282 | width4: '1' 283 | width5: '1' 284 | width6: '1' 285 | width7: '1' 286 | width8: '1' 287 | width9: '1' 288 | x_axis_label: '"x-Axis"' 289 | x_start: freq-(samp_rate/2) 290 | x_step: samp_rate/fftsize 291 | x_units: '""' 292 | y_axis_label: '"y-Axis"' 293 | y_units: '""' 294 | ymax: '10' 295 | ymin: '0' 296 | states: 297 | bus_sink: false 298 | bus_source: false 299 | bus_structure: null 300 | coordinate: [1048, 196] 301 | rotation: 0 302 | state: enabled 303 | 304 | connections: 305 | - [blocks_add_xx_0, '0', qtgui_vector_sink_f_0, '1'] 306 | - [blocks_file_source_0, '0', blocks_throttle_0, '0'] 307 | - [blocks_file_source_1, '0', blocks_add_xx_0, '1'] 308 | - [blocks_throttle_0, '0', blocks_add_xx_0, '0'] 309 | - [blocks_throttle_0, '0', qtgui_vector_sink_f_0, '0'] 310 | - [blocks_vector_source_x_0, '0', qtgui_vector_sink_f_0, '2'] 311 | 312 | metadata: 313 | file_format: 1 314 | -------------------------------------------------------------------------------- /specreceive.grc: -------------------------------------------------------------------------------- 1 | options: 2 | parameters: 3 | author: PE1RIK 4 | category: '[GRC Hier Blocks]' 5 | cmake_opt: '' 6 | comment: '' 7 | copyright: '' 8 | description: '' 9 | gen_cmake: 'On' 10 | gen_linking: dynamic 11 | generate_options: qt_gui 12 | hier_block_src_path: '.:' 13 | id: specreceive 14 | max_nouts: '0' 15 | output_language: python 16 | placement: (0,0) 17 | qt_qss_theme: '' 18 | realtime_scheduling: '' 19 | run: 'True' 20 | run_command: '{python} -u {filename}' 21 | run_options: prompt 22 | sizing_mode: fixed 23 | thread_safe_setters: '' 24 | title: Specmon_Receiver 25 | window_size: '' 26 | states: 27 | bus_sink: false 28 | bus_source: false 29 | bus_structure: null 30 | coordinate: [8, 8] 31 | rotation: 0 32 | state: enabled 33 | 34 | blocks: 35 | - name: threshold 36 | id: variable_qtgui_range 37 | parameters: 38 | comment: '' 39 | gui_hint: '' 40 | label: '' 41 | min_len: '200' 42 | orient: Qt.Horizontal 43 | rangeType: float 44 | start: '0' 45 | step: '.1' 46 | stop: '20' 47 | value: '8.0' 48 | widget: counter_slider 49 | states: 50 | bus_sink: false 51 | bus_source: false 52 | bus_structure: null 53 | coordinate: [704, 40.0] 54 | rotation: 0 55 | state: enabled 56 | - name: blocks_add_const_vxx_0 57 | id: blocks_add_const_vxx 58 | parameters: 59 | affinity: '' 60 | alias: '' 61 | comment: 'Constant is a value for correction to real dBm. 62 | 63 | Only to be used after calibration measurement.' 64 | const: ([calconst]*fftsize) 65 | maxoutbuf: '0' 66 | minoutbuf: '0' 67 | type: float 68 | vlen: fftsize 69 | states: 70 | bus_sink: false 71 | bus_source: false 72 | bus_structure: null 73 | coordinate: [320, 272.0] 74 | rotation: 0 75 | state: true 76 | - name: blocks_vector_source_x_0 77 | id: blocks_vector_source_x 78 | parameters: 79 | affinity: '' 80 | alias: '' 81 | comment: '' 82 | maxoutbuf: '0' 83 | minoutbuf: '0' 84 | repeat: 'True' 85 | tags: '[]' 86 | type: float 87 | vector: '[threshold+calconst]*fftsize' 88 | vlen: fftsize 89 | states: 90 | bus_sink: false 91 | bus_source: false 92 | bus_structure: null 93 | coordinate: [840, 368.0] 94 | rotation: 180 95 | state: disabled 96 | - name: blocks_vector_to_stream_0 97 | id: blocks_vector_to_stream 98 | parameters: 99 | affinity: '' 100 | alias: '' 101 | comment: '' 102 | maxoutbuf: '0' 103 | minoutbuf: '0' 104 | num_items: fftsize 105 | type: float 106 | vlen: '1' 107 | states: 108 | bus_sink: false 109 | bus_source: false 110 | bus_structure: null 111 | coordinate: [544, 488.0] 112 | rotation: 0 113 | state: true 114 | - name: calconst 115 | id: parameter 116 | parameters: 117 | alias: '' 118 | comment: '' 119 | hide: none 120 | label: calibration-constant 121 | short_id: c 122 | type: eng_float 123 | value: '-132' 124 | states: 125 | bus_sink: false 126 | bus_source: false 127 | bus_structure: null 128 | coordinate: [864, 44.0] 129 | rotation: 0 130 | state: true 131 | - name: fftsize 132 | id: parameter 133 | parameters: 134 | alias: '' 135 | comment: '' 136 | hide: none 137 | label: fft-size 138 | short_id: F 139 | type: intx 140 | value: '4096' 141 | states: 142 | bus_sink: false 143 | bus_source: false 144 | bus_structure: null 145 | coordinate: [280, 36.0] 146 | rotation: 0 147 | state: true 148 | - name: freq 149 | id: parameter 150 | parameters: 151 | alias: '' 152 | comment: '' 153 | hide: none 154 | label: Frequency 155 | short_id: f 156 | type: eng_float 157 | value: 48e6 158 | states: 159 | bus_sink: false 160 | bus_source: false 161 | bus_structure: null 162 | coordinate: [552, 36.0] 163 | rotation: 0 164 | state: true 165 | - name: qtgui_time_raster_sink_x_0 166 | id: qtgui_time_raster_sink_x 167 | parameters: 168 | affinity: '' 169 | alias: '' 170 | alpha1: '1.0' 171 | alpha10: '1.0' 172 | alpha2: '1.0' 173 | alpha3: '1.0' 174 | alpha4: '1.0' 175 | alpha5: '1.0' 176 | alpha6: '1.0' 177 | alpha7: '1.0' 178 | alpha8: '1.0' 179 | alpha9: '1.0' 180 | axislabels: 'False' 181 | color1: '0' 182 | color10: '0' 183 | color2: '0' 184 | color3: '0' 185 | color4: '0' 186 | color5: '0' 187 | color6: '0' 188 | color7: '0' 189 | color8: '0' 190 | color9: '0' 191 | comment: '' 192 | grid: 'True' 193 | gui_hint: tabje@1 194 | label1: '' 195 | label10: '' 196 | label2: '' 197 | label3: '' 198 | label4: '' 199 | label5: '' 200 | label6: '' 201 | label7: '' 202 | label8: '' 203 | label9: '' 204 | mult: '[]' 205 | name: '""' 206 | ncols: fftsize 207 | nconnections: '1' 208 | nrows: '500' 209 | offset: '[]' 210 | samp_rate: '5' 211 | type: float 212 | update_time: '0.10' 213 | zmax: '-110' 214 | zmin: '-130' 215 | states: 216 | bus_sink: false 217 | bus_source: false 218 | bus_structure: null 219 | coordinate: [808, 520.0] 220 | rotation: 0 221 | state: true 222 | - name: qtgui_vector_sink_f_0 223 | id: qtgui_vector_sink_f 224 | parameters: 225 | affinity: '' 226 | alias: '' 227 | alpha1: '1.0' 228 | alpha10: '1.0' 229 | alpha2: '1.0' 230 | alpha3: '1.0' 231 | alpha4: '1.0' 232 | alpha5: '1.0' 233 | alpha6: '1.0' 234 | alpha7: '1.0' 235 | alpha8: '1.0' 236 | alpha9: '1.0' 237 | autoscale: 'False' 238 | average: '1.0' 239 | color1: '"blue"' 240 | color10: '"dark blue"' 241 | color2: '"red"' 242 | color3: '"green"' 243 | color4: '"black"' 244 | color5: '"cyan"' 245 | color6: '"magenta"' 246 | color7: '"yellow"' 247 | color8: '"dark red"' 248 | color9: '"dark green"' 249 | comment: 'X-start: freq-(samp_rate/2) 250 | 251 | X-step: samp_rate/fftsize' 252 | grid: 'False' 253 | gui_hint: tabje@0 254 | label1: Original 255 | label10: '' 256 | label2: Threshold 257 | label3: Sorted 258 | label4: '' 259 | label5: '' 260 | label6: '' 261 | label7: '' 262 | label8: '' 263 | label9: '' 264 | maxoutbuf: '0' 265 | minoutbuf: '0' 266 | name: '""' 267 | nconnections: '3' 268 | ref_level: '0' 269 | showports: 'True' 270 | update_time: '0.10' 271 | vlen: fftsize 272 | width1: '1' 273 | width10: '1' 274 | width2: '1' 275 | width3: '1' 276 | width4: '1' 277 | width5: '1' 278 | width6: '1' 279 | width7: '1' 280 | width8: '1' 281 | width9: '1' 282 | x_axis_label: '"x-Axis"' 283 | x_start: freq-(samp_rate/2) 284 | x_step: samp_rate/fftsize 285 | x_units: '""' 286 | y_axis_label: '"y-Axis"' 287 | y_units: '""' 288 | ymax: '-110' 289 | ymin: '-130' 290 | states: 291 | bus_sink: false 292 | bus_source: false 293 | bus_structure: null 294 | coordinate: [848, 184.0] 295 | rotation: 0 296 | state: enabled 297 | - name: remote 298 | id: parameter 299 | parameters: 300 | alias: '' 301 | comment: 'Host to connect to. Format: 302 | 303 | tcp://:' 304 | hide: none 305 | label: remote-host 306 | short_id: r 307 | type: str 308 | value: tcp://sigint:50001 309 | states: 310 | bus_sink: false 311 | bus_source: false 312 | bus_structure: null 313 | coordinate: [64, 164.0] 314 | rotation: 0 315 | state: true 316 | - name: samp_rate 317 | id: parameter 318 | parameters: 319 | alias: '' 320 | comment: '' 321 | hide: none 322 | label: Sample-Rate 323 | short_id: s 324 | type: eng_float 325 | value: 2.5e6 326 | states: 327 | bus_sink: false 328 | bus_source: false 329 | bus_structure: null 330 | coordinate: [408, 36.0] 331 | rotation: 0 332 | state: true 333 | - name: tabje 334 | id: qtgui_tab_widget 335 | parameters: 336 | alias: '' 337 | comment: '' 338 | gui_hint: '' 339 | label0: Spectrum 340 | label1: Waterfall 341 | label10: Tab 10 342 | label11: Tab 11 343 | label12: Tab 12 344 | label13: Tab 13 345 | label14: Tab 14 346 | label15: Tab 15 347 | label16: Tab 16 348 | label17: Tab 17 349 | label18: Tab 18 350 | label19: Tab 19 351 | label2: Tab 2 352 | label3: Tab 3 353 | label4: Tab 4 354 | label5: Tab 5 355 | label6: Tab 6 356 | label7: Tab 7 357 | label8: Tab 8 358 | label9: Tab 9 359 | num_tabs: '2' 360 | states: 361 | bus_sink: false 362 | bus_source: false 363 | bus_structure: null 364 | coordinate: [224, 504.0] 365 | rotation: 0 366 | state: true 367 | - name: vector_sorter 368 | id: epy_block 369 | parameters: 370 | _source_code: "\"\"\"\nEmbedded Python Blocks:\n\nEach time this file is saved,\ 371 | \ GRC will instantiate the first class it finds\nto get ports and parameters\ 372 | \ of your block. The arguments to __init__ will\nbe the parameters. All of\ 373 | \ them are required to have default values!\n\"\"\"\n\nimport numpy as np\n\ 374 | from gnuradio import gr\n\n\nclass blk(gr.sync_block): # other base classes\ 375 | \ are basic_block, decim_block, interp_block\n \"\"\"Vector Sort And Threshold\ 376 | \ \n \n This block does 2 things:\n - Sort a vector with numpy. Output\ 377 | \ this vector on port 0\n \n - Calculate the median (50%) and add the\ 378 | \ threshold. Output a vector on port 1.\n \n \"\"\"\n\n def __init__(self,\ 379 | \ fftsize=4096, threshold=8.0): # only default arguments here\n \"\"\ 380 | \"arguments to this function show up as parameters in GRC\"\"\"\n self.threshold\ 381 | \ = threshold\n self.fftsize = fftsize\n gr.sync_block.__init__(\n\ 382 | \ self,\n name='Vector Sort And Threshold', # will show\ 383 | \ up in GRC\n in_sig=[(np.float32,fftsize)],\n out_sig=[(np.float32,fftsize),(np.float32,fftsize)]\n\ 384 | \ )\n # if an attribute with the same name as a parameter is found,\n\ 385 | \ # a callback is registered (properties work, too).\n #self.example_param\ 386 | \ = example_param\n\n def work(self, input_items, output_items):\n \ 387 | \ # Sort the list\n sortlist = np.sort(input_items[0])\n # Output\ 388 | \ the sorted list on output 0\n output_items[0][:] = sortlist\n \ 389 | \ # Determine the median\n vecmedian = np.median(sortlist[:(int(self.fftsize/2))])\n\ 390 | \ # Output the calculated threshold as vector on output 1\n output_items[1][:]\ 391 | \ = [self.threshold + vecmedian]*self.fftsize\n return len(output_items[0])\n" 392 | affinity: '' 393 | alias: '' 394 | comment: '' 395 | fftsize: fftsize 396 | maxoutbuf: '0' 397 | minoutbuf: '0' 398 | threshold: threshold 399 | states: 400 | _io_cache: ('Vector Sort And Threshold', 'blk', [('fftsize', '4096'), ('threshold', 401 | '8.0')], [('0', 'float', 4096)], [('0', 'float', 4096), ('1', 'float', 4096)], 402 | 'Vector Sort And Threshold \n \n This block does 2 things:\n - Sort 403 | a vector with numpy. Output this vector on port 0\n \n - Calculate the 404 | median (50%) and add the threshold. Output a vector on port 1.\n \n ', 405 | ['fftsize', 'threshold']) 406 | bus_sink: false 407 | bus_source: false 408 | bus_structure: null 409 | coordinate: [600, 344.0] 410 | rotation: 0 411 | state: true 412 | - name: zeromq_sub_source_0 413 | id: zeromq_sub_source 414 | parameters: 415 | address: remote 416 | affinity: '' 417 | alias: '' 418 | comment: '' 419 | hwm: '-1' 420 | maxoutbuf: '0' 421 | minoutbuf: '0' 422 | pass_tags: 'False' 423 | timeout: '100' 424 | type: float 425 | vlen: fftsize 426 | states: 427 | bus_sink: false 428 | bus_source: false 429 | bus_structure: null 430 | coordinate: [56, 332.0] 431 | rotation: 0 432 | state: true 433 | 434 | connections: 435 | - [blocks_add_const_vxx_0, '0', blocks_vector_to_stream_0, '0'] 436 | - [blocks_add_const_vxx_0, '0', qtgui_vector_sink_f_0, '0'] 437 | - [blocks_add_const_vxx_0, '0', vector_sorter, '0'] 438 | - [blocks_vector_source_x_0, '0', qtgui_vector_sink_f_0, '1'] 439 | - [blocks_vector_to_stream_0, '0', qtgui_time_raster_sink_x_0, '0'] 440 | - [vector_sorter, '0', qtgui_vector_sink_f_0, '2'] 441 | - [vector_sorter, '1', qtgui_vector_sink_f_0, '1'] 442 | - [zeromq_sub_source_0, '0', blocks_add_const_vxx_0, '0'] 443 | 444 | metadata: 445 | file_format: 1 446 | -------------------------------------------------------------------------------- /testspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # 3 | # Description: Tool to parse the logfiles to a daily log 4 | # 5 | # Author: Bart Somers PE1RIK 6 | 7 | from datetime import datetime 8 | import argparse 9 | 10 | # Parse the arguments 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument('-i', '--infile', type=str, help='Filename with output from specmon', required=True) 13 | parser.add_argument('-o', '--outfile', type=str, help='Filename where to put output', required=True) 14 | parser.add_argument('-v', '--version', type=int, help='Outputformat. use 2 for new format', required=False) 15 | parser.add_argument('-r', '--runtime', type=int, help='Runtime in seconds if not 3600', required=False) 16 | args = parser.parse_args() 17 | 18 | fhandler = open (args.infile, "r") 19 | outhandler = open (args.outfile, "a") 20 | 21 | # Check if other runtime is given 22 | if args.runtime: 23 | runtime = args.runtime 24 | else: 25 | runtime = 3600 26 | 27 | # Pre-define variables 28 | totaalverschil = 0 29 | start_uur = 0 30 | threshold = 0 31 | counter = 0 32 | dom = 0 33 | maxval = 0 34 | lastunder = 0 35 | lowsum = 0 36 | 37 | # Proces line by line 38 | for line in fhandler: 39 | array = line.split(',') 40 | if len(array) > 5: 41 | if array[0] == "A": 42 | verschil = float(array[5]) - float(array[2]) 43 | lastunder = float(array[5]) 44 | totaalverschil += verschil 45 | counter +=1 46 | # Determine the max of measurement over the hour 47 | if float(array[4]) > maxval: 48 | maxval = float(array[4]) 49 | # Sum the lowavg 50 | lowsum += float(array[1]) 51 | elif array[0] == "S": 52 | # Startup-line 53 | start_uur = array[3] 54 | threshold = array[5].rstrip() 55 | # Force the lastunder to be the end-time. 56 | lastunder = float(array[1]) + float(runtime) 57 | date_time = datetime.fromtimestamp(float(array[1])) 58 | dom = date_time.strftime("%d") 59 | dow = date_time.strftime("%w") 60 | elif array[0] == "A" and len(array) < 5: 61 | # Probably no "Under threshold" written 62 | verschil = abs(float(array[2]) - float(lastunder)) 63 | totaalverschil += verschil 64 | counter +=1 65 | 66 | # Calculate the percentage 67 | percentage = totaalverschil / (runtime/100) 68 | 69 | if counter == 0: 70 | average_open = 0 71 | average_low = 0 72 | else: 73 | average_open = totaalverschil / counter 74 | average_low = lowsum / counter 75 | 76 | if args.version == 2: 77 | # Print new version string 78 | print ('%s,%.2f,%.2f,%s,%i,%s,%.2f,%.2f,%s,%.2f' % ( start_uur, totaalverschil, percentage, threshold, counter, dom, average_open, maxval, dow, average_low ), file=outhandler ) 79 | else: 80 | # Print the original string 81 | print ('U %s V %.2f P %.2f T %s O %i D %s A %.2f M %.2f W %s L %.2f' % ( start_uur, totaalverschil, percentage, threshold, counter, dom, average_open, maxval, dow, average_low ), file=outhandler ) 82 | 83 | # Closing up 84 | fhandler.close() 85 | outhandler.close() 86 | 87 | exit(0) 88 | -------------------------------------------------------------------------------- /weekgraph: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | INPUT=$1 3 | gnuplot <<- EOF 4 | set terminal png size 1280,768 5 | set output '$INPUT-week.png' 6 | set xrange [0:23] 7 | set xlabel "Hour" 8 | set ylabel "Day" 9 | set cblabel "Percentage of usage" 10 | unset key 11 | load 'gnuplot-palettes/reds.pal' 12 | plot "$INPUT" using 2:12:6 with image pixels 13 | EOF 14 | --------------------------------------------------------------------------------