signal-1.4.5/0000755000000000000000000000000014456505401011170 5ustar0000000000000000signal-1.4.5/COPYING0000644000000000000000000010451514456505401012231 0ustar0000000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . signal-1.4.5/DESCRIPTION0000644000000000000000000000055214456505401012700 0ustar0000000000000000Name: signal Version: 1.4.5 Date: 2023-07-21 Author: various authors Maintainer: Mike Miller Title: Signal Processing Description: Signal processing tools, including filtering, windowing and display functions. Depends: octave (>= 3.8), control (>= 2.4) Autoload: no License: GPLv3+, public domain Url: https://octave.sourceforge.io/signal/ signal-1.4.5/INDEX0000644000000000000000000000377514456505401011776 0ustar0000000000000000signal >> Signal processing Signals buffer chirp cmorwavf diric gauspuls gmonopuls mexihat meyeraux morlet pulstran rectpuls sawtooth shanwavf shiftdata sigmoid_train specgram square tripuls udecode uencode unshiftdata vco Signal Measurement findpeaks peak2peak peak2rms rms rssq Correlation and Convolution cconv convmtx wconv xcorr xcorr2 xcov Filtering filtfilt filtic medfilt1 movingrms sgolayfilt sosfilt Filter Analysis filternorm filtord freqs freqs_plot fwhm grpdelay impz isallpass ismaxphase isminphase isstable phasez zplane Filter Conversion polystab residued residuez sos2ss sos2tf sos2zp ss2tf ss2zp tf2sos tf2ss tf2zp zp2sos zp2ss zp2tf IIR Filter Design besselap besself bilinear buttap butter buttord cheb cheb1ap cheb1ord cheb2ap cheb2ord cheby1 cheby2 ellip ellipap ellipord iirlp2mb impinvar invimpinvar firpm firpmord ncauer pei_tseng_notch sftrans FIR Filter Design cl2bp fir1 fir2 firls kaiserord qp_kaiser remez sgolay Transforms bitrevorder cceps cplxreal czt dct dct2 dctmtx dftmtx digitrevorder dst dwt fht fwht hilbert idct idct2 idst ifht ifwht rceps Power Spectrum Analysis ar_psd cohere cpsd csd db2pow mscohere pburg pow2db pwelch pyulear tfe tfestimate __power Window Functions barthannwin blackmanharris blackmannuttall bohmanwin boxcar chebwin flattopwin gaussian gausswin hann kaiser nuttallwin parzenwin rectwin triang tukeywin ultrwin welchwin window System Identification arburg aryule invfreq invfreqs invfreqz levinson lpc Sample Rate Change data2fun decimate downsample interp resample upfirdn upsample Pulse Metrics statelevels Utility buffer clustersegment fracshift marcumq primitive sampled2continuous schtrig upsamplefill wkeep wrev zerocrossing signal-1.4.5/NEWS0000644000000000000000000002252714456505401011677 0ustar0000000000000000Summary of important user-visible changes for signal 1.4.5: ---------------------------------------------------------- ** Added qt documentation ** Minor bug fixes and documentation improvements have been made to the following functions: db2pow findpeaks filtfilt firmpm sos2zp vco ** The following new functions have been added to the signal package: filtord filternorm isallpass ismaxphase isminphase phasez statelevels Summary of important user-visible changes for signal 1.4.4: ---------------------------------------------------------- ** Minor bug fixes and documentation improvements have been made to the following functions: sos2tf xcorr xcov zp2sos ** The following new functions have been added to the signal package: firpm firpmord istable lpc vco Summary of important user-visible changes for signal 1.4.3: ---------------------------------------------------------- ** Minor bug fixes and documentation improvements have been made to the following functions: fir2 remez residuez sos2tf sos2zp xcorr zp2sos Summary of important user-visible changes for signal 1.4.2: ---------------------------------------------------------- ** The compiled functions have been made compatible with recent changes in the development version of Octave. ** Minor bug fixes and documentation improvements have been made to the following functions: cplxreal cheb2ap buffer data2fun ss2zp clustersegmen ncauer cohere csd pburg pwelch pyulear tfe invfreq invfreqs invfreqz upfirdn ** The following new functions have been added to the signal package: sos2ss Summary of important user-visible changes for signal 1.4.1: ---------------------------------------------------------- ** Build failures introduced in the previous release on BSD and Windows systems have been fixed. ** The compiled functions have been made compatible with recent changes in the development version of Octave. ** Minor bug fixes and documentation improvements have been made to the following functions: butter rceps zplane filtfilt sos2tf filtic tukeywin Summary of important user-visible changes for signal 1.4.0: ---------------------------------------------------------- ** The buttord, cheb1ord, cheb2ord, and ellipord functions now support analog filter design with the "s" option. ** The cheb1ord and cheb2ord functions will now compute the filter order for band-stop or notch filters. ** The medfilt1 function has been completely rewritten to support additional arguments and options and to improve Matlab compatibility. ** The following new functions have been added to the signal package: cconv pow2db udecode db2pow rms uencode peak2peak rssq unshiftdata peak2rms shiftdata ** Other functions that have been changed for smaller bugfixes, increased Matlab compatibility, or performance: bitrevorder ellip primitive buffer findpeaks rectpuls butter fracshift schtrig cheby1 gauspuls sigmoid_train cheby2 gausswin specgram chirp impz square cplxreal invfreqs tripuls data2fun invfreqz digitrevorder marcumq Summary of important user-visible changes for signal 1.3.2: ---------------------------------------------------------- ** The package is no longer dependent on the general package. Summary of important user-visible changes for signal 1.3.1: ---------------------------------------------------------- ** The following window functions now accept a Matlab compatible option to select the periodic variant, useful for FFT applications: blackmanharris hann blackmannuttall nuttallwin ** The following filter design functions have improved and more consistent input parameter validation: buttord cheb2ord cheb1ord ellipord =============================================================================== signal-1.3.0 Release Date: 2014-01-26 Release Manager: Mike Miller =============================================================================== ** The following functions are new: digitrevorder upsamplefill primitive wconv ultrwin ** Several bugs have been fixed in the following functions: ellipord ifwht findpeaks remez fir1 resample fwht schtrig grpdelay zp2sos ** Replaced line continuation marker "\" by "..." to avoid deprecated syntax warning in Octave 3.8. ** The signal package now depends on Octave 3.8 or newer. The `ellipke' function is required, which used to be provided by the specfun package. Consequently, the signal package no longer depends on specfun. =============================================================================== signal-1.2.2 Release Date: 2013-03-25 Release Manager: Mike Miller =============================================================================== ** No change release to correct bad file permissions on previous release. =============================================================================== signal-1.2.1 Release Date: 2013-03-17 Release Manager: Mike Miller =============================================================================== ** The following functions are new: buttap cheb1ap cheb2ap ellipap findpeaks fwht ifwht ** Improved Matlab compatibility for the following window functions: barthannwin blackmanharris blackmannuttall chebwin flattopwin nuttallwin The changes include always returning a column vector, returning a valid window for a length argument of 1, and making all arguments after the length optional. ** Minor updates to documentation for the following functions: cpsd mscohere sos2tf sos2zp tfestimate zp2sos ** signal is no longer dependent on the optim package. =============================================================================== signal-1.2.0 Release Date: 2012-09-21 Release Manager: CarnĂ« Draug =============================================================================== ** Improved Matlab compability for the function `fir2'. This changes include always returning vaues in a row (even when the smoothing window is a single column), the default values for grid_n and ramp_n, and returning an error when invalid values are used (instead of silently adjusting them). ** Fixed failing tests for the following functions: fir1 pei_tseng_notch residued ** The function `rceps' was fixed to work correctly with odd-length inputs. ** Bugfix in `xcorr2' introduced in 1.1.2 that would not accept "none" as scale option. ** `xcorr2' scaling option "coeff" was changed to return the normalized cross-correlation. ** The following functions are new: movingrms schtrig clustersegment ** signal is no longer dependent on the image package. ** signal is now dependent on the general package. =============================================================================== signal-1.1.3 Release Date: 2012-05-12 Release Manager: CarnĂ« Draug =============================================================================== ** signal is no longer dependent on the audio package. ** signal is now dependent on the image package. ** The function `marcumq' was imported from the communications package and has been completely rewritten to improve performance and fix computational errors. ** Package is no longer automatically loaded. ** The functions `__ellip_ws' and `__ellip_ws_min' have been removed (they are now subfunctions of `ncauer'. ** The function `blackmanharris' was fixed to have even symmetry. =============================================================================== signal-1.1.2 Release Date: 2012-01-06 Release Manager: Lukas Reichlin =============================================================================== * Added the following filter conversion functions: ss2tf ss2zp tf2ss tf2zp zp2ss zp2tf =============================================================================== signal-1.1.1 Release Date: 2011-11-06 Release Manager: Juan Pablo Carbajal =============================================================================== * Following function now show help text correctly instead of copyright notice: downsample dst flattopwin fwhm idst square upsample * Apply pathc by Paul Dreik to cl2bp_lib.h. =============================================================================== signal-1.1.0 Release Date: 2011-11-04 Release Manager: Juan Pablo Carbajal =============================================================================== * Minor bug fixes in: blackmannuttall.m xcorr.m filtfilt.m invfreq.m invfreqs.m resample.m * New functions added: data2fun.m impinvar.m invimpinvar.m sigmoid_train.m pei_tseng_notch.m iirlp2mb.m * Not implemented functions removed from the documentation. * All demos are now working! signal-1.4.5/doc/0000755000000000000000000000000014456505401011735 5ustar0000000000000000signal-1.4.5/doc/functions.texi0000644000000000000000000063616514456505401014661 0ustar0000000000000000@c --------------------------------------------------- @node Signals @section Signals @cindex Signals @c Signals buffer @c ----------------------------------------- @subsection buffer @cindex buffer @deftypefn {Function File} {@var{y} =} buffer (@var{x}, @var{n}, @var{p}, @var{opt}) @deftypefnx {Function File} {[@var{y}, @var{z}, @var{opt}] =} buffer (@dots{}) Buffer a signal into a data frame. The arguments to @code{buffer} are @table @asis @item @var{x} The data to be buffered. @item @var{n} The number of rows in the produced data buffer. This is an positive integer value and must be supplied. @item @var{p} An integer less than @var{n} that specifies the under- or overlap between column in the data frame. The default value of @var{p} is 0. @item @var{opt} In the case of an overlap, @var{opt} can be either a vector of length @var{p} or the string 'nodelay'. If @var{opt} is a vector, then the first @var{p} entries in @var{y} will be filled with these values. If @var{opt} is the string 'nodelay', then the first value of @var{y} corresponds to the first value of @var{x}. In the can of an underlap, @var{opt} must be an integer between 0 and @code{-@var{p}}. The represents the initial underlap of the first column of @var{y}. The default value for @var{opt} the vector @code{zeros (1, @var{p})} in the case of an overlap, or 0 otherwise. @end table In the case of a single output argument, @var{y} will be padded with zeros to fill the missing values in the data frame. With two output arguments @var{z} is the remaining data that has not been used in the current data frame. Likewise, the output @var{opt} is the overlap, or underlap that might be used for a future call to @code{code} to allow continuous buffering. @end deftypefn @c Signals chirp @c ----------------------------------------- @subsection chirp @cindex chirp @deftypefn {Function File} {} chirp (@var{t}) @deftypefnx {Function File} {} chirp (@var{t}, @var{f0}) @deftypefnx {Function File} {} chirp (@var{t}, @var{f0}, @var{t1}) @deftypefnx {Function File} {} chirp (@var{t}, @var{f0}, @var{t1}, @var{f1}) @deftypefnx {Function File} {} chirp (@var{t}, @var{f0}, @var{t1}, @var{f1}, @var{shape}) @deftypefnx {Function File} {} chirp (@var{t}, @var{f0}, @var{t1}, @var{f1}, @var{shape}, @var{phase}) Evaluate a chirp signal at time @var{t}. A chirp signal is a frequency swept cosine wave. @table @var @item t vector of times to evaluate the chirp signal @item f0 frequency at time t=0 [ 0 Hz ] @item t1 time t1 [ 1 sec ] @item f1 frequency at time t=t1 [ 100 Hz ] @item shape shape of frequency sweep 'linear' f(t) = (f1-f0)*(t/t1) + f0 'quadratic' f(t) = (f1-f0)*(t/t1)^2 + f0 'logarithmic' f(t) = (f1/f0)^(t/t1) * f0 @item phase phase shift at t=0 @end table For example: @example @group @c doctest: +SKIP specgram (chirp ([0:0.001:5])); # default linear chirp of 0-100Hz in 1 sec specgram (chirp ([-2:0.001:15], 400, 10, 100, "quadratic")); soundsc (chirp ([0:1/8000:5], 200, 2, 500, "logarithmic"), 8000); @end group @end example If you want a different sweep shape f(t), use the following: @group @verbatim y = cos (2 * pi * integral (f(t)) + phase); @end verbatim @end group @end deftypefn @c Signals cmorwavf @c ----------------------------------------- @subsection cmorwavf @cindex cmorwavf @deftypefn {Function File} {[@var{psi}, @var{x}] =} cmorwavf (@var{lb}, @var{ub}, @var{n}, @var{fb}, @var{fc}) Compute the Complex Morlet wavelet. @end deftypefn @c Signals diric @c ----------------------------------------- @subsection diric @cindex diric @deftypefn {Function File} {@var{y} =} diric (@var{x},@var{n}) Compute the dirichlet function. @xseealso{sinc, gauspuls, sawtooth} @end deftypefn @c Signals gauspuls @c ----------------------------------------- @subsection gauspuls @cindex gauspuls @deftypefn {Function File} {@var{y} =} gauspuls (@var{t}) @deftypefnx {Function File} {@var{y} =} gauspuls (@var{t}, @var{fc}) @deftypefnx {Function File} {@var{y} =} gauspuls (@var{t}, @var{fc}, @var{bw}) Generate a Gaussian modulated sinusoidal pulse sampled at times @var{t}. @xseealso{pulstran, rectpuls, tripuls} @end deftypefn @c Signals gmonopuls @c ----------------------------------------- @subsection gmonopuls @cindex gmonopuls @deftypefn {Function File} {@var{y} =} gmonopuls (@var{t},@var{fc}) Return the gaussian monopulse. @end deftypefn @c Signals mexihat @c ----------------------------------------- @subsection mexihat @cindex mexihat @deftypefn {Function File} {[@var{psi}, @var{x}] =} mexihat (@var{lb}, @var{ub}, @var{n}) Compute the Mexican hat wavelet. @end deftypefn @c Signals meyeraux @c ----------------------------------------- @subsection meyeraux @cindex meyeraux @deftypefn {Function File} {@var{y} =} meyeraux (@var{x}) Compute the Meyer wavelet auxiliary function. @end deftypefn @c Signals morlet @c ----------------------------------------- @subsection morlet @cindex morlet @deftypefn {Function File} {[@var{psi}, @var{x}] =} morlet (@var{lb}, @var{ub}, @var{n}) Compute the Morlet wavelet. @end deftypefn @c Signals pulstran @c ----------------------------------------- @subsection pulstran @cindex pulstran @deftypefn {Function File} {@var{y} =} pulstran (@var{t}, @var{d}, @var{func}, @dots{}) @deftypefnx {Function File} {@var{y} =} pulstran (@var{t}, @var{d}, @var{p}) @deftypefnx {Function File} {@var{y} =} pulstran (@var{t}, @var{d}, @var{p}, @var{Fs}) @deftypefnx {Function File} {@var{y} =} pulstran (@var{t}, @var{d}, @var{p}, @var{Fs}, @var{method}) Generate the signal y=sum(func(t+d,...)) for each d. If d is a matrix of two columns, the first column is the delay d and the second column is the amplitude a, and y=sum(a*func(t+d)) for each d,a. Clearly, func must be a function which accepts a vector of times. Any extra arguments needed for the function must be tagged on the end. Example: @example fs = 11025; # arbitrary sample rate f0 = 100; # pulse train sample rate w = 0.001; # pulse width of 1 millisecond auplot (pulstran (0:1/fs:0.1, 0:1/f0:0.1, "rectpuls", w), fs); @end example If instead of a function name you supply a pulse shape sampled at frequency Fs (default 1 Hz), an interpolated version of the pulse is added at each delay d. The interpolation stays within the the time range of the delayed pulse. The interpolation method defaults to linear, but it can be any interpolation method accepted by the function interp1. Example: @example fs = 11025; # arbitrary sample rate f0 = 100; # pulse train sample rate w = boxcar(10); # pulse width of 1 millisecond at 10 kHz auplot (pulstran (0:1/fs:0.1, 0:1/f0:0.1, w, 10000), fs); @end example @end deftypefn @c Signals rectpuls @c ----------------------------------------- @subsection rectpuls @cindex rectpuls @deftypefn {Function File} {@var{y} =} rectpuls (@var{t}) @deftypefnx {Function File} {@var{y} =} rectpuls (@var{t}, @var{w}) Generate a rectangular pulse over the interval [-@var{w}/2,@var{w}/2), sampled at times @var{t}. This is useful with the function @code{pulstran} for generating a series of pulses. Example: @example @group fs = 11025; # arbitrary sample rate f0 = 100; # pulse train sample rate w = 0.3/f0; # pulse width 3/10th the distance between pulses plot (pulstran (0:1/fs:4/f0, 0:1/f0:4/f0, "rectpuls", w)); @end group @end example @xseealso{gauspuls, pulstran, tripuls} @end deftypefn @c Signals sawtooth @c ----------------------------------------- @subsection sawtooth @cindex sawtooth @deftypefn {Function File} {@var{y} =} sawtooth (@var{t}) @deftypefnx {Function File} {@var{y} =} sawtooth (@var{t}, @var{width}) Generates a sawtooth wave of period @code{2 * pi} with limits @code{+1/-1} for the elements of @var{t}. @var{width} is a real number between @code{0} and @code{1} which specifies the point between @code{0} and @code{2 * pi} where the maximum is. The function increases linearly from @code{-1} to @code{1} in @code{[0, 2 * pi * @var{width}]} interval, and decreases linearly from @code{1} to @code{-1} in the interval @code{[2 * pi * @var{width}, 2 * pi]}. If @var{width} is 0.5, the function generates a standard triangular wave. If @var{width} is not specified, it takes a value of 1, which is a standard sawtooth function. @end deftypefn @c Signals shanwavf @c ----------------------------------------- @subsection shanwavf @cindex shanwavf @deftypefn {Function File} {[@var{psi}, @var{x}] =} shanwavf (@var{lb}, @var{ub}, @var{n}, @var{fb}, @var{fc}) Compute the Complex Shannon wavelet. @end deftypefn @c Signals shiftdata @c ----------------------------------------- @subsection shiftdata @cindex shiftdata @deftypefn {Function File} {[@var{out perm shifts}] =} shiftdata (@var{in}) @deftypefnx {Function File} {[@var{out perm shifts}] =} shiftdata (@var{in}, @var{dim}) Shift data @var{in} to permute the dimension @var{dim} to the first column. @xseealso{unshiftdata} @end deftypefn @c Signals sigmoid_train @c ----------------------------------------- @subsection sigmoid_train @cindex sigmoid_train @deftypefn {Function File} {[@var{y} @var{s}] =} sigmoid_train (@var{t}, @var{ranges}, @var{rc}) Evaluate a train of sigmoid functions at @var{t}. The number and duration of each sigmoid is determined from @var{ranges}. Each row of @var{ranges} represents a real interval, e.g. if sigmoid @code{i} starts at @code{t=0.1} and ends at @code{t=0.5}, then @code{@var{ranges}(i,:) = [0.1 0.5]}. The input @var{rc} is an array that defines the rising and falling time constants of each sigmoid. Its size must equal the size of @var{ranges}. The individual sigmoids are returned in @var{s}. The combined sigmoid train is returned in the vector @var{y} of length equal to @var{t}, and such that @code{Y = max (S)}. Run @code{demo sigmoid_train} to some examples of the use of this function. @end deftypefn @c Signals specgram @c ----------------------------------------- @subsection specgram @cindex specgram @deftypefn {Function File} {} specgram (@var{x}) @deftypefnx {Function File} {} specgram (@var{x}, @var{n}) @deftypefnx {Function File} {} specgram (@var{x}, @var{n}, @var{Fs}) @deftypefnx {Function File} {} specgram (@var{x}, @var{n}, @var{Fs}, @var{window}) @deftypefnx {Function File} {} specgram (@var{x}, @var{n}, @var{Fs}, @var{window}, @var{overlap}) @deftypefnx {Function File} {[@var{S}, @var{f}, @var{t}] =} specgram (@dots{}) Generate a spectrogram for the signal @var{x}. The signal is chopped into overlapping segments of length @var{n}, and each segment is windowed and transformed into the frequency domain using the FFT. The default segment size is 256. If @var{fs} is given, it specifies the sampling rate of the input signal. The argument @var{window} specifies an alternate window to apply rather than the default of @code{hanning (@var{n})}. The argument @var{overlap} specifies the number of samples overlap between successive segments of the input signal. The default overlap is @code{length (@var{window})/2}. If no output arguments are given, the spectrogram is displayed. Otherwise, @var{S} is the complex output of the FFT, one row per slice, @var{f} is the frequency indices corresponding to the rows of @var{S}, and @var{t} is the time indices corresponding to the columns of @var{S}. Example: @example @group x = chirp([0:0.001:2],0,2,500); # freq. sweep from 0-500 over 2 sec. Fs=1000; # sampled every 0.001 sec so rate is 1 kHz step=ceil(20*Fs/1000); # one spectral slice every 20 ms window=ceil(100*Fs/1000); # 100 ms data window specgram(x, 2^nextpow2(window), Fs, window, window-step); ## Speech spectrogram [x, Fs] = auload(file_in_loadpath("sample.wav")); # audio file step = fix(5*Fs/1000); # one spectral slice every 5 ms window = fix(40*Fs/1000); # 40 ms data window fftn = 2^nextpow2(window); # next highest power of 2 [S, f, t] = specgram(x, fftn, Fs, window, window-step); S = abs(S(2:fftn*4000/Fs,:)); # magnitude in range 0= minF & f <= maxF); Then there is the choice of colormap. A brightness varying colormap such as copper or bone gives good shape to the ridges and valleys. A hue varying colormap such as jet or hsv gives an indication of the steepness of the slopes. The final spectrogram is displayed in log energy scale and by convention has low frequencies on the bottom of the image: imagesc(t, f, flipud(log(S(idx,:)))); @end deftypefn @c Signals square @c ----------------------------------------- @subsection square @cindex square @deftypefn {Function File} {@var{s} =} square (@var{t}, @var{duty}) @deftypefnx {Function File} {@var{s} =} square (@var{t}) Generate a square wave of period 2 pi with limits +1/-1. If @var{duty} is specified, it is the percentage of time the square wave is "on". The square wave is +1 for that portion of the time. @verbatim on time * 100 duty cycle = ------------------ on time + off time @end verbatim @xseealso{cos, sawtooth, sin, tripuls} @end deftypefn @c Signals tripuls @c ----------------------------------------- @subsection tripuls @cindex tripuls @deftypefn {Function File} {@var{y} =} tripuls (@var{t}) @deftypefnx {Function File} {@var{y} =} tripuls (@var{t}, @var{w}) @deftypefnx {Function File} {@var{y} =} tripuls (@var{t}, @var{w}, @var{skew}) Generate a triangular pulse over the interval [-@var{w}/2,@var{w}/2), sampled at times @var{t}. This is useful with the function @code{pulstran} for generating a series of pulses. @var{skew} is a value between -1 and 1, indicating the relative placement of the peak within the width. -1 indicates that the peak should be at -@var{w}/2, and 1 indicates that the peak should be at @var{w}/2. The default value is 0. Example: @example @group fs = 11025; # arbitrary sample rate f0 = 100; # pulse train sample rate w = 0.3/f0; # pulse width 3/10th the distance between pulses plot (pulstran (0:1/fs:4/f0, 0:1/f0:4/f0, "tripuls", w)); @end group @end example @xseealso{gauspuls, pulstran, rectpuls} @end deftypefn @c Signals udecode @c ----------------------------------------- @subsection udecode @cindex udecode @deftypefn {Function File} {@var{out} =} udecode (@var{in}, @var{n}) @deftypefnx {Function File} {@var{out} =} udecode (@var{in}, @var{n}, @var{v}) @deftypefnx {Function File} {@var{out} =} udecode (@var{in}, @var{n}, @var{v}, @var{overflows}) Invert the operation of uencode. @xseealso{uencode} @end deftypefn @c Signals uencode @c ----------------------------------------- @subsection uencode @cindex uencode @deftypefn {Function File} {@var{out} =} uencode (@var{in}, @var{n}) @deftypefnx {Function File} {@var{out} =} uencode (@var{in}, @var{n}, @var{v}) @deftypefnx {Function File} {@var{out} =} uencode (@var{in}, @var{n}, @var{v}, @var{signed}) Quantize the entries of the array @var{in} using 2^@var{n} quantization levels. @xseealso{udecode} @end deftypefn @c Signals unshiftdata @c ----------------------------------------- @subsection unshiftdata @cindex unshiftdata @deftypefn {Function File} {[@var{out}] =} unshiftdata (@var{in}, @var{perm}, @var{shifts}) Reverse what is done by shiftdata. @xseealso{shiftdata} @end deftypefn @c Signals vco @c ----------------------------------------- @subsection vco @cindex vco @deftypefn {} {y =} vco (@var{x}, @var{fc}, @var{fs}) @deftypefnx {} {y =} vco (@var{x}, [@var{fmin}, @var{fmax}], @var{fs}) Creates a signal that oscillates at a frequency determined by input @var{x} with a sampling frequency @var{fs}. Inputs: @itemize @item @var{x} - input data with a range of -1 to 1. A value of -1 means no output, 0 cuoreesponds to @var{fc}, and 1 corresponds to 2*@var{fc}. @item @var{fc} - Carrier frequency @item @var{fs} - Sampling rate @item @var{fmin}, @var{fmax} - Frequency modulation range limits. @end itemize Outputs: @itemize @item @var{y} - output signal @end itemize @end deftypefn @c --------------------------------------------------- @node Signal Measurement @section Signal Measurement @cindex Signal Measurement @c Signal Measurement findpeaks @c ----------------------------------------- @subsection findpeaks @cindex findpeaks @deftypefn {Function File} {[@var{pks}, @var{loc}, @var{extra}] =} findpeaks (@var{data}) @deftypefnx {Function File} {@dots{} =} findpeaks (@dots{}, @var{property}, @var{value}) @deftypefnx {Function File} {@dots{} =} findpeaks (@dots{}, @asis{"DoubleSided"}) Finds peaks on @var{data}. Peaks of a positive array of data are defined as local maxima. For double-sided data, they are maxima of the positive part and minima of the negative part. @var{data} is expected to be a single column vector. The function returns the value of @var{data} at the peaks in @var{pks}. The index indicating their position is returned in @var{loc}. The third output argument is a structure with additional information: @table @asis @item "parabol" A structure containing the parabola fitted to each returned peak. The structure has two fields, @asis{"x"} and @asis{"pp"}. The field @asis{"pp"} contains the coefficients of the 2nd degree polynomial and @asis{"x"} the extrema of the interval where it was fitted. @item "height" The estimated height of the returned peaks (in units of @var{data}). @item "baseline" The height at which the roots of the returned peaks were calculated (in units of @var{data}). @item "roots" The abscissa values (in index units) at which the parabola fitted to each of the returned peaks realizes its width as defined below. @end table This function accepts property-value pair given in the list below: @table @asis @item "MinPeakHeight" Minimum peak height (non-negative scalar). Only peaks that exceed this value will be returned. For data taking positive and negative values use the option "DoubleSided". Default value @code{eps}. @item "MinPeakDistance" Minimum separation between (positive integer). Peaks separated by less than this distance are considered a single peak. This distance is also used to fit a second order polynomial to the peaks to estimate their width, therefore it acts as a smoothing parameter. The neighborhood size is equal to the value of @asis{"MinPeakDistance"}. Default value 1. @item "MinPeakWidth" Minimum width of peaks (positive integer). The width of the peaks is estimated using a parabola fitted to the neighborhood of each peak. The width is caulculated with the formula @group a * (width - x0)^2 = 1 @end group where a is the the concavity of the parabola and x0 its vertex. Default value 1. @item "MaxPeakWidth" Maximum width of peaks (positive integer). Default value @code{Inf}. @item "DoubleSided" Tells the function that data takes positive and negative values. The base-line for the peaks is taken as the mean value of the function. This is equivalent as passing the absolute value of the data after removing the mean. @end table Run @command{demo findpeaks} to see some examples. @end deftypefn @c Signal Measurement peak2peak @c ----------------------------------------- @subsection peak2peak @cindex peak2peak @deftypefn {Function File} {@var{y} =} peak2peak (@var{x}) @deftypefnx {Function File} {@var{y} =} peak2peak (@var{x}, @var{dim}) Compute the difference between the maximum and minimum values in the vector @var{x}. If @var{x} is a matrix, compute the difference for each column and return them in a row vector. If the optional argument @var{dim} is given, operate along this dimension. @xseealso{max, min, peak2rms, rms, rssq} @end deftypefn @c Signal Measurement peak2rms @c ----------------------------------------- @subsection peak2rms @cindex peak2rms @deftypefn {Function File} {@var{y} =} peak2rms (@var{x}) @deftypefnx {Function File} {@var{y} =} peak2rms (@var{x}, @var{dim}) Compute the ratio of the largest absolute value to the root-mean-square (RMS) value of the vector @var{x}. If @var{x} is a matrix, compute the peak-magnitude-to-RMS ratio for each column and return them in a row vector. If the optional argument @var{dim} is given, operate along this dimension. @xseealso{max, min, peak2peak, rms, rssq} @end deftypefn @c Signal Measurement rms @c ----------------------------------------- @subsection rms @cindex rms @deftypefn {Function File} {@var{y} =} rms (@var{x}) @deftypefnx {Function File} {@var{y} =} rms (@var{x}, @var{dim}) Compute the root-mean-square (RMS) of the vector @var{x}. The root-mean-square is defined as @tex $$ {\rm rms}(x) = {\sqrt{\sum_{i=1}^N {x_i}^2 \over N}} $$ @end tex @ifnottex @example rms (@var{x}) = SQRT (1/N SUM_i @var{x}(i)^2) @end example @end ifnottex If @var{x} is a matrix, compute the root-mean-square for each column and return them in a row vector. If the optional argument @var{dim} is given, operate along this dimension. @xseealso{mean, meansq, peak2rms, rssq, sumsq} @end deftypefn @c Signal Measurement rssq @c ----------------------------------------- @subsection rssq @cindex rssq @deftypefn {Function File} {@var{y} =} rssq (@var{x}) @deftypefnx {Function File} {@var{y} =} rssq (@var{x}, @var{dim}) Compute the root-sum-of-squares (RSS) of the vector @var{x}. The root-sum-of-squares is defined as @tex $$ {\rm rssq}(x) = {\sqrt{\sum_{i=1}^N {x_i}^2}} $$ @end tex @ifnottex @example rssq (@var{x}) = SQRT (SUM_i @var{x}(i)^2) @end example @end ifnottex If @var{x} is a matrix, compute the root-sum-of-squares for each column and return them in a row vector. If the optional argument @var{dim} is given, operate along this dimension. @xseealso{mean, meansq, sumsq, rms} @end deftypefn @c --------------------------------------------------- @node Correlation and Convolution @section Correlation and Convolution @cindex Correlation and Convolution @c Correlation and Convolution cconv @c ----------------------------------------- @subsection cconv @cindex cconv @deftypefn {Function File} {@var{c} =} cconv (@var{a}, @var{b}, @var{n}) @deftypefnx {Function File} {@var{c} =} cconv (@var{a}, @var{b}) Compute the modulo-N circular convolution. @var{a} and @var{b} are input vectors and @var{c} is the modolo-@var{n} convolution of @var{a} and @var{b}. If @var{n} is not provided, its assumed default value is @code{length(@var{a}) + length(@var{b}) - 1}, which provides the same result as a linear convolution. Examples: @example @group cconv (1:2, 1:4) @result{} 1 4 7 10 8 @end group @end example @example @group cconv (1:2, 1:4, 2) @result{} 16 14 @end group @end example @example @group cconv (1:2, 1:4, 4) @result{} 9 4 7 10 @end group @end example @xseealso{conv, circshift} @end deftypefn @c Correlation and Convolution convmtx @c ----------------------------------------- @subsection convmtx @cindex convmtx @deftypefn {Function File} {} convmtx (@var{a}, @var{n}) If @var{a} is a column vector and @var{x} is a column vector of length @var{n}, then @code{convmtx(@var{a}, @var{n}) * @var{x}} gives the convolution of of @var{a} and @var{x} and is the same as @code{conv(@var{a}, @var{x})}. The difference is if many vectors are to be convolved with the same vector, then this technique is possibly faster. Similarly, if @var{a} is a row vector and @var{x} is a row vector of length @var{n}, then @code{@var{x} * convmtx(@var{a}, @var{n})} is the same as @code{conv(@var{x}, @var{a})}. @end deftypefn @xseealso{conv} @c Correlation and Convolution wconv @c ----------------------------------------- @subsection wconv @cindex wconv @deftypefn {Function File} {@var{y} =} wconv (@var{type}, @var{x}, @var{f}) @deftypefnx {Function File} {@var{y} =} wconv (@var{type}, @var{x}, @var{f}, @var{shape}) 1-D or 2-D convolution. @strong{Inputs} @table @var @item type Type of convolution. @item x Signal vector or matrix. @item f Coefficients of @acronym{FIR} filter. @item shape Shape. @end table @strong{Outputs} @table @var @item y Convoluted signal. @end table @end deftypefn @c Correlation and Convolution xcorr @c ----------------------------------------- @subsection xcorr @cindex xcorr @deftypefn {Function File} {[@var{R}, @var{lag}] =} xcorr ( @var{X} ) @deftypefnx {Function File} {@dots{} =} xcorr ( @var{X}, @var{Y} ) @deftypefnx {Function File} {@dots{} =} xcorr ( @dots{}, @var{maxlag}) @deftypefnx {Function File} {@dots{} =} xcorr ( @dots{}, @var{scale}) Estimates the cross-correlation. Estimate the cross correlation R_xy(k) of vector arguments @var{X} and @var{Y} or, if @var{Y} is omitted, estimate autocorrelation R_xx(k) of vector @var{X}, for a range of lags k specified by argument "maxlag". If @var{X} is a matrix, each column of @var{X} is correlated with itself and every other column. The cross-correlation estimate between vectors "x" and "y" (of length N) for lag "k" is given by @tex $$ R_{xy}(k) = \sum_{i=1}^{N} x_{i+k} \conj(y_i), @end tex @ifnottex @example @group N R_xy(k) = sum x_@{i+k@} conj(y_i), i=1 @end group @end example @end ifnottex where data not provided (for example x(-1), y(N+1)) is zero. Note the definition of cross-correlation given above. To compute a cross-correlation consistent with the field of statistics, see @command{xcov}. @strong{ARGUMENTS} @table @var @item X [non-empty; real or complex; vector or matrix] data @item Y [real or complex vector] data If @var{X} is a matrix (not a vector), @var{Y} must be omitted. @var{Y} may be omitted if @var{X} is a vector; in this case xcorr estimates the autocorrelation of @var{X}. @item maxlag [integer scalar] maximum correlation lag If omitted, the default value is N-1, where N is the greater of the lengths of @var{X} and @var{Y} or, if @var{X} is a matrix, the number of rows in @var{X}. @item scale [character string] specifies the type of scaling applied to the correlation vector (or matrix). is one of: @table @samp @item none return the unscaled correlation, R, @item biased return the biased average, R/N, @item unbiased return the unbiased average, R(k)/(N-|k|), @item coeff or normalized return the correlation coefficient, R/(rms(x).rms(y)), where "k" is the lag, and "N" is the length of @var{X}. If omitted, the default value is "none". If @var{Y} is supplied but does not have the same length as @var{X}, scale must be "none". @end table @end table @strong{RETURNED VARIABLES} @table @var @item R array of correlation estimates @item lag row vector of correlation lags [-maxlag:maxlag] @end table The array of correlation estimates has one of the following forms: (1) Cross-correlation estimate if @var{X} and @var{Y} are vectors. (2) Autocorrelation estimate if is a vector and @var{Y} is omitted. (3) If @var{X} is a matrix, R is an matrix containing the cross-correlation estimate of each column with every other column. Lag varies with the first index so that R has 2*maxlag+1 rows and P^2 columns where P is the number of columns in @var{X}. If Rij(k) is the correlation between columns i and j of @var{X} @code{R(k+maxlag+1,P*(i-1)+j) == Rij(k)} for lag k in [-maxlag:maxlag], or @code{R(:,P*(i-1)+j) == xcorr(X(:,i),X(:,j))}. @code{reshape(R(k,:),P,P)} is the cross-correlation matrix for @code{X(k,:)}. @xseealso{xcov} @end deftypefn @c Correlation and Convolution xcorr2 @c ----------------------------------------- @subsection xcorr2 @cindex xcorr2 @deftypefn {Function File} {} xcorr2 (@var{a}) @deftypefnx {Function File} {} xcorr2 (@var{a}, @var{b}) @deftypefnx {Function File} {} xcorr2 (@dots{}, @var{scale}) Compute the 2D cross-correlation of matrices @var{a} and @var{b}. If @var{b} is not specified, computes autocorrelation of @var{a}, i.e., same as @code{xcorr (@var{a}, @var{a})}. The optional argument @var{scale}, defines the type of scaling applied to the cross-correlation matrix. Possible values are: @table @asis @item "none" (default) No scaling. @item "biased" Scales the raw cross-correlation by the maximum number of elements of @var{a} and @var{b} involved in the generation of any element of @var{c}. @item "unbiased" Scales the raw correlation by dividing each element in the cross-correlation matrix by the number of products @var{a} and @var{b} used to generate that element. @item "coeff" Scales the normalized cross-correlation on the range of [0 1] so that a value of 1 corresponds to a correlation coefficient of 1. @end table @xseealso{conv2, corr2, xcorr} @end deftypefn @c Correlation and Convolution xcov @c ----------------------------------------- @subsection xcov @cindex xcov @deftypefn {Function File} {[@var{R}, @var{lag}] =} xcov ( @var{X} ) @deftypefnx {Function File} {@dots{} =} xcov ( @var{X}, @var{Y} ) @deftypefnx {Function File} {@dots{} =} xcov ( @dots{}, @var{maxlag}) @deftypefnx {Function File} {@dots{} =} xcov ( @dots{}, @var{scale}) Compute covariance at various lags [=correlation(x-mean(x),y-mean(y))]. @table @var @item X input vector @item Y if specified, compute cross-covariance between X and Y, otherwise compute autocovariance of X. @item maxlag is specified, use lag range [-maxlag:maxlag], otherwise use range [-n+1:n-1]. @item scale: @table @samp @item biased for covariance=raw/N, @item unbiased for covariance=raw/(N-|lag|), @item coeff for covariance=raw/(covariance at lag 0), @item none for covariance=raw @item none is the default. @end table @end table Returns the covariance for each lag in the range, plus an optional vector of lags. @xseealso{xcorr} @end deftypefn @c --------------------------------------------------- @node Filtering @section Filtering @cindex Filtering @c Filtering filtfilt @c ----------------------------------------- @subsection filtfilt @cindex filtfilt @deftypefn {Function File} {@var{y} =} filtfilt (@var{b}, @var{a}, @var{x}) Forward and reverse filter the signal. This corrects for phase distortion introduced by a one-pass filter, though it does square the magnitude response in the process. That's the theory at least. In practice the phase correction is not perfect, and magnitude response is distorted, particularly in the stop band. Example @example @group [b, a]=butter(3, 0.1); # 5 Hz low-pass filter t = 0:0.01:1.0; # 1 second sample x=sin(2*pi*t*2.3)+0.25*randn(size(t)); # 2.3 Hz sinusoid+noise y = filtfilt(b,a,x); z = filter(b,a,x); # apply filter plot(t,x,';data;',t,y,';filtfilt;',t,z,';filter;') @end group @end example @end deftypefn @c Filtering filtic @c ----------------------------------------- @subsection filtic @cindex filtic @deftypefn {Function File} {@var{zf} =} filtic (@var{b}, @var{a}, @var{y}) @deftypefnx {Function File} {@var{zf} =} filtic (@var{b}, @var{a}, @var{y}, @var{x}) Set initial condition vector for filter function The vector zf has the same values that would be obtained from function filter given past inputs x and outputs y The vectors x and y contain the most recent inputs and outputs respectively, with the newest values first: x = [x(-1) x(-2) ... x(-nb)], nb = length(b)-1 y = [y(-1) y(-2) ... y(-na)], na = length(a)-a If length(x) p. By default, p=3 and n=p+2 or n=p+3 if p is even. If @var{f} is given as a matrix, it is expected to be a filter as computed by @code{sgolay}. These filters are particularly good at preserving lineshape while removing high frequency squiggles. Particularly, compare a 5 sample averager, an order 5 butterworth lowpass filter (cutoff 1/3) and sgolayfilt(x, 3, 5), the best cubic estimated from 5 points: @example @group [b, a] = butter (5, 1/3); x = [zeros(1,15), 10*ones(1,10), zeros(1,15)]; plot (sgolayfilt (x), "r;sgolayfilt;", ... filtfilt (ones (1,5)/5, 1, x), "g;5 sample average;", ... filtfilt (b, a, x), "c;order 5 butterworth;", ... x, "+b;original data;"); @end group @end example @xseealso{sgolay} @end deftypefn @c Filtering sosfilt @c ----------------------------------------- @subsection sosfilt @cindex sosfilt @deftypefn {Loadable Function} {@var{y} =} sosfilt (@var{sos}, @var{x}) Second order section IIR filtering of @var{x}. The second order section filter is described by the matrix @var{sos} with: @multitable {col 1} {this is column two} @item @tab [ @var{B1} @var{A1} ]@* @item @var{sos} = @tab [ @dots{} ],@* @item @tab [ @var{BN} @var{AN} ]@* @end multitable where @code{@var{B1} = [b0 b1 b2]} and @code{@var{A1} = [1 a1 a2]} for section 1, etc. The b0 entry must be nonzero for each section. @end deftypefn @c --------------------------------------------------- @node Filter Analysis @section Filter Analysis @cindex Filter Analysis @c Filter Analysis filternorm @c ----------------------------------------- @subsection filternorm @cindex filternorm @deftypefn {Function File} {@var{L} = } filternorm (@var{b}, @var{a}) @deftypefnx {Function File} {@var{L} = } filternorm (@var{b}, @var{a}, @var{pnorm}) @deftypefnx {Function File} {@var{L} = } filternorm (@var{b}, @var{a}, 2, @var{tol}) Compute the 2-norm of a digital filter defined by the numerator coefficients, @var{b}, and the denominator coefficients, @var{a}. It is also possible to compute the infinity-norm by passing inf in the @var{pnorm} parameter. @var{pnorm} only accepts 2 or inf. Example: @example [b, a] = butter (8, 0.5); filternorm (b, a) @end example @end deftypefn @c Filter Analysis filtord @c ----------------------------------------- @subsection filtord @cindex filtord @deftypefn {Function File} {@var{n} = } filtord (@var{b}, @var{a}) @deftypefnx {Function File} {@var{n} = } filtord (@var{sos}) Returns the filter order @var{n} for a filter defined by the numerator coefficients, @var{b}, and the denominator coefficients, @var{a}. It also accepts a filter defined by a matrix of second-order sections, @var{sos}. Example: @example [b, a] = butter (8, 0.5); filtord (b, a) @end example @end deftypefn @c Filter Analysis freqs @c ----------------------------------------- @subsection freqs @cindex freqs @deftypefn {Function File} {@var{h} =} freqs (@var{b}, @var{a}, @var{w}) @deftypefnx {Function File} {} freqs (@var{b}, @var{a}, @var{w}) Compute the s-plane frequency response of the IIR filter B(s)/A(s) as H = polyval(B,j*W)./polyval(A,j*W). If called with no output argument, a plot of magnitude and phase are displayed. Example: @example b = [1 2]; a = [1 1]; w = linspace (0, 4, 128); freqs (b, a, w); @end example @end deftypefn @c Filter Analysis freqs_plot @c ----------------------------------------- @subsection freqs_plot @cindex freqs_plot @deftypefn {Function File} {} freqs_plot (@var{w}, @var{h}) Plot the amplitude and phase of the vector @var{h}. @end deftypefn @c Filter Analysis fwhm @c ----------------------------------------- @subsection fwhm @cindex fwhm @deftypefn {Function File} {@var{f} =} fwhm (@var{y}) @deftypefnx {Function File} {@var{f} =} fwhm (@var{x}, @var{y}) @deftypefnx {Function File} {@var{f} =} fwhm (@dots{}, "zero") @deftypefnx {Function File} {@var{f} =} fwhm (@dots{}, "min") @deftypefnx {Function File} {@var{f} =} fwhm (@dots{}, "alevel", @var{level}) @deftypefnx {Function File} {@var{f} =} fwhm (@dots{}, "rlevel", @var{level}) Compute peak full-width at half maximum (FWHM) or at another level of peak maximum for vector or matrix data @var{y}, optionally sampled as @math{y(x)}. If @var{y} is a matrix, return FWHM for each column as a row vector. The default option "zero" computes fwhm at half maximum, i.e. @math{0.5*max(y)}. The option "min" computes fwhm at the middle curve, i.e. @math{0.5*(min(y)+max(y))}. The option "rlevel" computes full-width at the given relative level of peak profile, i.e. at @math{rlevel*max(y)} or @math{rlevel*(min(y)+max(y))}, respectively. For example, @code{fwhm (@dots{}, "rlevel", 0.1)} computes full width at 10 % of peak maximum with respect to zero or minimum; FWHM is equivalent to @code{fwhm(@dots{}, "rlevel", 0.5)}. The option "alevel" computes full-width at the given absolute level of @var{y}. Return 0 if FWHM does not exist (e.g. monotonous function or the function does not cut horizontal line at @math{rlevel*max(y)} or @math{rlevel*(max(y)+min(y))} or alevel, respectively). @end deftypefn @c Filter Analysis grpdelay @c ----------------------------------------- @subsection grpdelay @cindex grpdelay @deftypefn {Function File} {[@var{g}, @var{w}] =} grpdelay (@var{b}) @deftypefnx {Function File} {[@var{g}, @var{w}] =} grpdelay (@var{b}, @var{a}) @deftypefnx {Function File} {[@var{g}, @var{w}] =} grpdelay (@dots{}, @var{n}) @deftypefnx {Function File} {[@var{g}, @var{w}] =} grpdelay (@dots{}, @var{n}, "whole") @deftypefnx {Function File} {[@var{g}, @var{f}] =} grpdelay (@dots{}, @var{n}, @var{Fs}) @deftypefnx {Function File} {[@var{g}, @var{f}] =} grpdelay (@dots{}, @var{n}, "whole", @var{Fs}) @deftypefnx {Function File} {[@var{g}, @var{w}] =} grpdelay (@dots{}, @var{w}) @deftypefnx {Function File} {[@var{g}, @var{f}] =} grpdelay (@dots{}, @var{f}, @var{Fs}) @deftypefnx {Function File} {} grpdelay (@dots{}) Compute the group delay of a filter. [g, w] = grpdelay(b) returns the group delay g of the FIR filter with coefficients b. The response is evaluated at 512 angular frequencies between 0 and pi. w is a vector containing the 512 frequencies. The group delay is in units of samples. It can be converted to seconds by multiplying by the sampling period (or dividing by the sampling rate fs). [g, w] = grpdelay(b,a) returns the group delay of the rational IIR filter whose numerator has coefficients b and denominator coefficients a. [g, w] = grpdelay(b,a,n) returns the group delay evaluated at n angular frequencies. For fastest computation n should factor into a small number of small primes. [g, w] = grpdelay(b,a,n,'whole') evaluates the group delay at n frequencies between 0 and 2*pi. [g, f] = grpdelay(b,a,n,Fs) evaluates the group delay at n frequencies between 0 and Fs/2. [g, f] = grpdelay(b,a,n,'whole',Fs) evaluates the group delay at n frequencies between 0 and Fs. [g, w] = grpdelay(b,a,w) evaluates the group delay at frequencies w (radians per sample). [g, f] = grpdelay(b,a,f,Fs) evaluates the group delay at frequencies f (in Hz). grpdelay(...) plots the group delay vs. frequency. If the denominator of the computation becomes too small, the group delay is set to zero. (The group delay approaches infinity when there are poles or zeros very close to the unit circle in the z plane.) Theory: group delay, g(w) = -d/dw [arg@{H(e^jw)@}], is the rate of change of phase with respect to frequency. It can be computed as: @example d/dw H(e^-jw) g(w) = ------------- H(e^-jw) @end example where @example H(z) = B(z)/A(z) = sum(b_k z^k)/sum(a_k z^k). @end example By the quotient rule, @example A(z) d/dw B(z) - B(z) d/dw A(z) d/dw H(z) = ------------------------------- A(z) A(z) @end example Substituting into the expression above yields: @example A dB - B dA g(w) = ----------- = dB/B - dA/A A B @end example Note that, @example d/dw B(e^-jw) = sum(k b_k e^-jwk) d/dw A(e^-jw) = sum(k a_k e^-jwk) @end example which is just the FFT of the coefficients multiplied by a ramp. As a further optimization when nfft>>length(a), the IIR filter (b,a) is converted to the FIR filter conv(b,fliplr(conj(a))). For further details, see http://ccrma.stanford.edu/~jos/filters/Numerical_Computation_Group_Delay.html @end deftypefn @c Filter Analysis impz @c ----------------------------------------- @subsection impz @cindex impz @deftypefn {Function File} {[@var{x}, @var{t}] =} impz (@var{b}) @deftypefnx {Function File} {[@var{x}, @var{t}] =} impz (@var{b}, @var{a}) @deftypefnx {Function File} {[@var{x}, @var{t}] =} impz (@var{b}, @var{a}, @var{n}) @deftypefnx {Function File} {[@var{x}, @var{t}] =} impz (@var{b}, @var{a}, @var{n}, @var{fs}) @deftypefnx {Function File} {} impz (@dots{}) Generate impulse-response characteristics of the filter. The filter coefficients correspond to the the z-plane rational function with numerator b and denominator a. If a is not specified, it defaults to 1. If n is not specified, or specified as [], it will be chosen such that the signal has a chance to die down to -120dB, or to not explode beyond 120dB, or to show five periods if there is no significant damping. If no return arguments are requested, plot the results. @xseealso{freqz, zplane} @end deftypefn @c Filter Analysis isallpass @c ----------------------------------------- @subsection isallpass @cindex isallpass @deftypefn {Function File} {@var{L} = } isallpass (@var{b}, @var{a}) @deftypefnx {Function File} {@var{L} = } isallpass (@var{sos}) Determine whether a digital filter is allpass. The filter might be defined by the numerator coefficients, @var{b}, and the denominator coefficients, @var{a}, or, alternatively, by a matrix of second-order sections, @var{sos}. Example: @example a = [1 2 3]; b = [3 2 1]; isallpass (b, a) @end example Ref [1] Shyu, Jong-Jy, & Pei, Soo-Chang, A new approach to the design of complex all-pass IIR digital filters, Signal Processing, 40(2–3), 207–215, 1994. https://doi.org/10.1016/0165-1684(94)90068-x Ref [2] Vaidyanathan, P. P. Multirate Systems and Filter Banks. 1st edition, Pearson College Div, 1992. @end deftypefn @c Filter Analysis ismaxphase @c ----------------------------------------- @subsection ismaxphase @cindex ismaxphase @deftypefn {Function File} {@var{L} = } ismaxphase (@var{b}, @var{a}) @deftypefnx {Function File} {@var{L} = } ismaxphase (@var{sos}) @deftypefnx {Function File} {@var{L} = } ismaxphase (@dots{}, @var{tol}) Determine whether a digital filter is maximum phase (maximum energy-delay). The filter might be defined by the numerator coefficients, @var{b}, and the denominator coefficients, @var{a}, or, alternatively, by a matrix of second-order sections, @var{sos}. A tolerance @var{tol} might be given to define when two numbers are close enough to be considered equal. Example: @example b = [1 2 4 4 2 1]; zplane (b); ismaxphase (b) @end example Ref [1] Oppenheim, Alan, and Ronald Schafer. Discrete-Time Signal Processing. 3rd edition, Pearson, 2009. @end deftypefn @c Filter Analysis isminphase @c ----------------------------------------- @subsection isminphase @cindex isminphase @deftypefn {Function File} {@var{L} = } isminphase (@var{b}, @var{a}) @deftypefnx {Function File} {@var{L} = } isminphase (@var{sos}) @deftypefnx {Function File} {@var{L} = } isminphase (@dots{}, @var{tol}) Determine whether a digital filter is minimum phase. The filter might be defined by the numerator coefficients, @var{b}, and the denominator coefficients, @var{a}, or, alternatively, by a matrix of second-order sections, @var{sos}. A toleranve @var{tol} might be given to define when two numbers are close enough to be considered equal. Example: @example a = [1 0.5]; b = [3 1]; isminphase (b, a) @end example Ref [1] Oppenheim, Alan, and Ronald Schafer. Discrete-Time Signal Processing. 3rd edition, Pearson, 2009. @end deftypefn @c Filter Analysis isstable @c ----------------------------------------- @subsection isstable @cindex isstable @deftypefn {Function File} {@var{FLAG} =} isstable (@var{B}, @var{A}) Returns a logical output equal to TRUE, if the filter is stable. This can be done with coeffients of the filer @var{B} and @var{A}. Alternatively by using a second order sections matrix (SOS). Inputs: @itemize @item @var{B}: Numerator coefficients of the filter @item @var{A}: Denominator coeffients of the filter. Can be an empty vector. @end itemize Output: @itemize @item @var{FLAG}: Returns a logical output, equal to TRUE if the filter is stable. @end itemize Examples: @example b = [1 2 3 4 5 5 1 2]; a = [4 5 6 7 9 10 4 6]; flag = isstable (b, a) flag = 0 @end example Using SOS @example [z, p, k] = butter (6, 0.7, 'high'); sos = zp2sos (z, p, k); flag = isstable (sos) flag = 1 @end example @end deftypefn @c Filter Analysis phasez @c ----------------------------------------- @subsection phasez @cindex phasez @deftypefn {Function File} {[@var{phi}, @var{w}] = } phasez (@var{b}, @var{a}, @var{n}) @deftypefnx {Function File} {[@var{phi}, @var{w}] = } phasez (@var{b}, @var{a}) @deftypefnx {Function File} {[@var{phi}, @var{w}] = } phasez (@var{sos}, @var{n}) @deftypefnx {Function File} {[@var{phi}, @var{w}] = } phasez (@var{sos}) @deftypefnx {Function File} {[@var{phi}, @var{w}] = } phasez (@dots{}, @var{n}, "whole") @deftypefnx {Function File} {[@var{phi}, @var{w}] = } phasez (@dots{}, @var{n}, Fs) @deftypefnx {Function File} {} phasez (@dots{}) Compute the phase response of digital filter defined either by its coefficients (@var{b} and @var{a} are the numerator and denominator coefficients respectively) or by its second-order sections representation, given by the matrix @var{sos}. The output @var{phi} is the phase response computed in a vector the vector of frequencies @var{w}. The phase response is evaluated at @var{n} angular frequencies between 0 and @ifnottex pi. @end ifnottex @tex $\pi$. @end tex @noindent If @var{a} is omitted, the denominator is assumed to be 1 (this corresponds to a simple FIR filter). If @var{n} is omitted, a value of 512 is assumed. If the third/forth argument, @qcode{"whole"}, is given, the response is evaluated at @var{n} angular frequencies between 0 and @ifnottex 2*pi. @end ifnottex @tex $\pi$. @end tex It is possible also to pass the value @qcode{"half"}, which will lead to the default behaviour. Example: @example [b, a] = butter (2, [.15,.3]); phasez (b, a); @end example Ref [1] Oppenheim, Alan, and Ronald Schafer. Discrete-Time Signal Processing. 3rd edition, Pearson, 2009. @xseealso{freqz, phasedelay} @end deftypefn @c Filter Analysis zplane @c ----------------------------------------- @subsection zplane @cindex zplane @deftypefn {Function File} {} zplane (@var{z}, @var{p}) @deftypefnx {Function File} {} zplane (@var{b}, @var{a}) Plot the poles and zeros on a complex plane. If the arguments are column vectors @var{z} and @var{p}, the complex zeros @var{z} and poles @var{p} are displayed. If the arguments are row vectors @var{b} and @var{a}, the zeros and poles of the transfer function represented by these filter coefficients are displayed. If @var{z} and @var{p} are matrices, the columns are distinct sets of zeros and poles and are displayed together in distinct colors. Note that due to the nature of the @code{roots} function, poles and zeros may be displayed as occurring around a circle rather than at a single point. The transfer function is @example @group B(z) b0 + b1 z^(-1) + b2 z^(-2) + ... + bM z^(-M) H(z) = ---- = -------------------------------------------- A(z) a0 + a1 z^(-1) + a2 z^(-2) + ... + aN z^(-N) b0 (z - z1) (z - z2) ... (z - zM) = -- z^(-M+N) ------------------------------ a0 (z - p1) (z - p2) ... (z - pN) @end group @end example If called with only one argument, the poles @var{p} defaults to an empty vector, and the denominator coefficient vector @var{a} defaults to 1. @end deftypefn @c --------------------------------------------------- @node Filter Conversion @section Filter Conversion @cindex Filter Conversion @c Filter Conversion polystab @c Filter Conversion residued @c ----------------------------------------- @subsection residued @cindex residued @deftypefn {Function File} {[@var{r}, @var{p}, @var{f}, @var{m}] =} residued (@var{b}, @var{a}) Compute the partial fraction expansion (PFE) of filter @math{H(z) = B(z)/A(z)}. In the usual PFE function @code{residuez}, the IIR part (poles @var{p} and residues @var{r}) is driven @emph{in parallel} with the FIR part (@var{f}). In this variant, the IIR part is driven by the @emph{output} of the FIR part. This structure can be more accurate in signal modeling applications. INPUTS: @var{b} and @var{a} are vectors specifying the digital filter @math{H(z) = B(z)/A(z)}. See @code{help filter} for documentation of the @var{b} and @var{a} filter coefficients. RETURNED: @itemize @item @var{r} = column vector containing the filter-pole residues @item @var{p} = column vector containing the filter poles @item @var{f} = row vector containing the FIR part, if any @item @var{m} = column vector of pole multiplicities @end itemize EXAMPLES: @example See @code{test residued verbose} to see a number of examples. @end example For the theory of operation, see @indicateurl{http://ccrma.stanford.edu/~jos/filters/residued.html} @xseealso{residue, residued} @end deftypefn @c Filter Conversion residuez @c ----------------------------------------- @subsection residuez @cindex residuez @deftypefn {Function File} {[@var{r}, @var{p}, @var{f}, @var{m}] =} residuez (@var{b}, @var{a}) Compute the partial fraction expansion of filter @math{H(z) = B(z)/A(z)}. INPUTS: @var{b} and @var{a} are vectors specifying the digital filter @math{H(z) = B(z)/A(z)}. See @code{help filter} for documentation of the @var{b} and @var{a} filter coefficients. RETURNED: @itemize @item @var{r} = column vector containing the filter-pole residues @item @var{p} = column vector containing the filter poles @item @var{f} = row vector containing the FIR part, if any @item @var{m} = column vector of pole multiplicities @end itemize EXAMPLES: @example See @code{test residuez verbose} to see a number of examples. @end example For the theory of operation, see @indicateurl{http://ccrma.stanford.edu/~jos/filters/residuez.html} @xseealso{residue, residued} @end deftypefn @c Filter Conversion sos2ss @c ----------------------------------------- @subsection sos2ss @cindex sos2ss @deftypefn {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} sos2ss (@var{sos}) Convert series second-order sections to state-space. @xseealso{sos2ss, ss2tf} @end deftypefn @c Filter Conversion sos2tf @c ----------------------------------------- @subsection sos2tf @cindex sos2tf @deftypefn {Function File} {[@var{b}, @var{a}] =} sos2tf (@var{sos}) @deftypefnx {Function File} {[@var{b}, @var{a}] =} sos2tf (@var{sos}, @var{g}) Convert series second-order sections to transfer function. INPUTS: @itemize @item @var{sos} = matrix of series second-order sections, one per row: @example @var{sos} = [@var{B1}.' @var{A1}.'; ...; @var{BN}.' @var{AN}.'] @end example where @code{@var{B1}.' = [b0 b1 b2] and @var{A1}.' = [a0 a1 a2]} for section 1, etc. a0 is usually equal to 1 because all 2nd order transfer functions can be scaled so that a0 = 1. However, this is not mandatory for this implementation, which supports all kinds of transfer functions, including first order transfer functions. See @code{filter} for documentation of the second-order direct-form filter coefficients @var{B}i and @var{A}i. @item @var{g} is an overall gain factor that effectively scales the output @var{b} vector (or any one of the input @var{B}i vectors). If not given the gain is assumed to be 1. @end itemize RETURNED: @var{b} and @var{a} are vectors specifying the analog or digital filter @math{H(s) = B(s)/A(s)} or @math{H(z) = B(z)/A(z)}. See @code{filter} for further details. @xseealso{tf2sos, zp2sos, sos2pz, zp2tf, tf2zp} @end deftypefn @c Filter Conversion sos2zp @c ----------------------------------------- @subsection sos2zp @cindex sos2zp @deftypefn {Function File} {[@var{z}, @var{p}, @var{k}] =} sos2zp (@var{sos}) @deftypefnx {Function File} {[@var{z}, @var{p}, @var{k}] =} sos2zp (@var{sos}, @var{g}) Convert series second-order sections to zeros, poles, and gains (pole residues). INPUTS: @itemize @item @var{sos} = matrix of series second-order sections, one per row: @example @var{sos} = [@var{B1}.' @var{A1}.'; ...; @var{BN}.' @var{AN}.'] @end example where @code{@var{B1}.' = [b0 b1 b2] and @var{A1}.' = [a0 a1 a2]} for section 1, etc. a0 is usually equal to 1 because all 2nd order transfer functions can be scaled so that a0 = 1. However, this is not mandatory for this implementation, which supports all kinds of transfer functions, including first order transfer functions. See @code{filter} for documentation of the second-order direct-form filter coefficients @var{B}i and @var{A}i. @item @var{g} is an overall gain factor that effectively scales any one of the input @var{B}i vectors. If not given the gain is assumed to be 1. @end itemize RETURNED: @itemize @item @var{z} = column-vector containing all zeros (roots of B(z)) @item @var{p} = column-vector containing all poles (roots of A(z)) @item @var{k} = overall gain = @var{B}(Inf) @end itemize EXAMPLE: @example [z, p, k] = sos2zp ([1 0 1, 1 0 -0.81; 1 0 0, 1 0 0.49]) @result{} z = 0 + 1i 0 - 1i 0 + 0i 0 + 0i @result{} p = -0.9000 + 0i 0.9000 + 0i 0 + 0.7000i 0 - 0.7000i @result{} k = 1 @end example @xseealso{zp2sos, sos2tf, tf2sos, zp2tf, tf2zp} @end deftypefn @c Filter Conversion ss2tf @c ----------------------------------------- @subsection ss2tf @cindex ss2tf @deftypefn {Function File} {[@var{num}, @var{den}] =} ss2tf (@var{a}, @var{b}, @var{c}, @var{d}) Conversion from state-space to transfer function representation. The state space system: @tex $$ \dot x = Ax + Bu $$ $$ y = Cx + Du $$ @end tex @ifnottex @example @group . x = Ax + Bu y = Cx + Du @end group @end example @end ifnottex is converted to a transfer function: @tex $$ G(s) = { { \rm num }(s) \over { \rm den }(s) } $$ @end tex @ifnottex @example @group num(s) G(s)=------- den(s) @end group @end example @end ifnottex @end deftypefn @c Filter Conversion ss2zp @c ----------------------------------------- @subsection ss2zp @cindex ss2zp @deftypefn {Function File} {[@var{z}, @var{p}, @var{k}] =} ss2zp (@var{a}, @var{b}, @var{c}, @var{d}) Converts a state space representation to a set of poles and zeros; @var{k} is a gain associated with the zeros. @end deftypefn @c Filter Conversion tf2sos @c ----------------------------------------- @subsection tf2sos @cindex tf2sos @deftypefn {Function File} {[@var{sos}, @var{g}] =} tf2sos (@var{b}, @var{a}) @deftypefnx {Function File} {@var{sos} =} tf2sos (@var{b}, @var{a}) Convert direct-form filter coefficients to series second-order sections. INPUTS: @var{b} and @var{a} are vectors specifying the digital filter @math{H(z) = B(z)/A(z)}. See @code{filter} for documentation of the @var{b} and @var{a} filter coefficients. RETURNED: @itemize @item @var{sos} = matrix of series second-order sections, one per row: @example @var{sos} = [@var{b1}.' @var{a1}.'; ...; @var{bn}.' @var{an}.'] @end example where @code{@var{B1}.' = [b0 b1 b2] and @var{A1}.' = [1 a1 a2]} for section 1, etc. The b0 entry must be nonzero for each section (zeros at infinity not supported). @item @var{g} is an overall gain factor that effectively scales any one of the @var{B}i vectors. @end itemize If called with only one output argument, the overall filter gain is applied to the first second-order section in the matrix @var{sos}. EXAMPLE: @example B = [1 0 0 0 0 1]; A = [1 0 0 0 0 .9]; [sos, g] = tf2sos (B, A) sos = 1.00000 0.61803 1.00000 1.00000 0.60515 0.95873 1.00000 -1.61803 1.00000 1.00000 -1.58430 0.95873 1.00000 1.00000 -0.00000 1.00000 0.97915 -0.00000 g = 1 @end example @xseealso{sos2tf, zp2sos, sos2pz, zp2tf, tf2zp} @end deftypefn @c Filter Conversion tf2ss @c ----------------------------------------- @subsection tf2ss @cindex tf2ss @deftypefn {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} tf2ss (@var{num}, @var{den}) Conversion from transfer function to state-space. The state space system: @tex $$ \dot x = Ax + Bu $$ $$ y = Cx + Du $$ @end tex @ifnottex @example @group . x = Ax + Bu y = Cx + Du @end group @end example @end ifnottex is obtained from a transfer function: @tex $$ G(s) = { { \rm num }(s) \over { \rm den }(s) } $$ @end tex @ifnottex @example @group num(s) G(s)=------- den(s) @end group @end example @end ifnottex The state space system matrices obtained from this function will be in observable companion form as Wolovich's Observable Structure Theorem is used. @end deftypefn @c Filter Conversion tf2zp @c ----------------------------------------- @subsection tf2zp @cindex tf2zp @deftypefn {Function File} {[@var{z}, @var{p}, @var{k}] =} tf2zp (@var{num}, @var{den}) Convert transfer functions to poles-and-zero representations. Returns the zeros and poles of the system defined by @var{num}/@var{den}. @var{k} is a gain associated with the system zeros. @end deftypefn @c Filter Conversion zp2sos @c ----------------------------------------- @subsection zp2sos @cindex zp2sos @deftypefn {Function File} {[@var{sos}, @var{g}] =} zp2sos (@var{z}) @deftypefnx {Function File} {[@var{sos}, @var{g}] =} zp2sos (@var{z}, @var{p}) @deftypefnx {Function File} {[@var{sos}, @var{g}] =} zp2sos (@var{z}, @var{p}, @var{k}) @deftypefnx {Function File} {@var{sos} =} zp2sos (@dots{}) Convert filter poles and zeros to second-order sections. INPUTS: @itemize @item @var{z} = column-vector containing the filter zeros @item @var{p} = column-vector containing the filter poles @item @var{k} = overall filter gain factor. If not given the gain is assumed to be 1. @end itemize RETURNED: @itemize @item @var{sos} = matrix of series second-order sections, one per row: @example @var{sos} = [@var{B1}.' @var{A1}.'; ...; @var{BN}.' @var{AN}.'] @end example where @code{@var{B1}.' = [b0 b1 b2] and @var{A1}.' = [a0 a1 a2]} for section 1, etc. See @code{filter} for documentation of the second-order direct-form filter coefficients @var{B}i and %@var{A}i, i=1:N. @item @var{g} is the overall gain factor that effectively scales any one of the @var{B}i vectors. @end itemize If called with only one output argument, the overall filter gain is applied to the first second-order section in the matrix @var{sos}. EXAMPLE: @example [z, p, k] = tf2zp ([1 0 0 0 0 1], [1 0 0 0 0 .9]); [sos, g] = zp2sos (z, p, k) sos = 1.0000 0.6180 1.0000 1.0000 0.6051 0.9587 1.0000 -1.6180 1.0000 1.0000 -1.5843 0.9587 1.0000 1.0000 0 1.0000 0.9791 0 g = 1 @end example @xseealso{sos2zp, sos2tf, tf2sos, zp2tf, tf2zp} @end deftypefn @c Filter Conversion zp2ss @c ----------------------------------------- @subsection zp2ss @cindex zp2ss @deftypefn {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} zp2ss (@var{z}, @var{p}, @var{k}) Conversion from zero / pole to state space. @strong{Inputs} @table @var @item z @itemx p Vectors of (possibly) complex poles and zeros of a transfer function. Complex values must come in conjugate pairs (i.e., @math{x+jy} in @var{z} means that @math{x-jy} is also in @var{z}). @item k Real scalar (leading coefficient). @end table @strong{Outputs} @table @var @item @var{a} @itemx @var{b} @itemx @var{c} @itemx @var{d} The state space system, in the form: @tex $$ \dot x = Ax + Bu $$ $$ y = Cx + Du $$ @end tex @ifnottex @example @group . x = Ax + Bu y = Cx + Du @end group @end example @end ifnottex @end table @end deftypefn @c Filter Conversion zp2tf @c ----------------------------------------- @subsection zp2tf @cindex zp2tf @deftypefn {Function File} {[@var{num}, @var{den}] =} zp2tf (@var{z}, @var{p}, @var{k}) Converts zeros / poles to a transfer function. @strong{Inputs} @table @var @item z @itemx p Vectors of (possibly complex) poles and zeros of a transfer function. Complex values must appear in conjugate pairs. @item k Real scalar (leading coefficient). @end table @end deftypefn @c --------------------------------------------------- @node IIR Filter Design @section IIR Filter Design @cindex IIR Filter Design @c IIR Filter Design besselap @c ----------------------------------------- @subsection besselap @cindex besselap @deftypefn {Function File} {[@var{zero}, @var{pole}, @var{gain}] =} besselap (@var{n}) Return bessel analog filter prototype. References: http://en.wikipedia.org/wiki/Bessel_polynomials @end deftypefn @c IIR Filter Design besself @c ----------------------------------------- @subsection besself @cindex besself @deftypefn {Function File} {[@var{b}, @var{a}] =} besself (@var{n}, @var{w}) @deftypefnx {Function File} {[@var{b}, @var{a}] =} besself (@var{n}, @var{w}, "high") @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} besself (@dots{}) @deftypefnx {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} besself (@dots{}) @deftypefnx {Function File} {[@dots{}] =} besself (@dots{}, "z") Generate a Bessel filter. Default is a Laplace space (s) filter. [b,a] = besself(n, Wc) low pass filter with cutoff pi*Wc radians [b,a] = besself(n, Wc, 'high') high pass filter with cutoff pi*Wc radians [z,p,g] = besself(...) return filter as zero-pole-gain rather than coefficients of the numerator and denominator polynomials. [...] = besself(...,'z') return a discrete space (Z) filter, W must be less than 1. [a,b,c,d] = besself(...) return state-space matrices References: Proakis & Manolakis (1992). Digital Signal Processing. New York: Macmillan Publishing Company. @end deftypefn @c IIR Filter Design bilinear @c ----------------------------------------- @subsection bilinear @cindex bilinear @deftypefn {Function File} {[@var{Zb}, @var{Za}] =} bilinear (@var{Sb}, @var{Sa}, @var{T}) @deftypefnx {Function File} {[@var{Zb}, @var{Za}] =} bilinear (@var{Sz}, @var{Sp}, @var{Sg}, @var{T}) @deftypefnx {Function File} {[@var{Zz}, @var{Zp}, @var{Zg}] =} bilinear (@dots{}) Transform a s-plane filter specification into a z-plane specification. Filters can be specified in either zero-pole-gain or transfer function form. The input form does not have to match the output form. 1/T is the sampling frequency represented in the z plane. Note: this differs from the bilinear function in the signal processing toolbox, which uses 1/T rather than T. Theory: Given a piecewise flat filter design, you can transform it from the s-plane to the z-plane while maintaining the band edges by means of the bilinear transform. This maps the left hand side of the s-plane into the interior of the unit circle. The mapping is highly non-linear, so you must design your filter with band edges in the s-plane positioned at 2/T tan(w*T/2) so that they will be positioned at w after the bilinear transform is complete. The following table summarizes the transformation: @example +---------------+-----------------------+----------------------+ | Transform | Zero at x | Pole at x | | H(S) | H(S) = S-x | H(S)=1/(S-x) | +---------------+-----------------------+----------------------+ | 2 z-1 | zero: (2+xT)/(2-xT) | zero: -1 | | S -> - --- | pole: -1 | pole: (2+xT)/(2-xT) | | T z+1 | gain: (2-xT)/T | gain: (2-xT)/T | +---------------+-----------------------+----------------------+ @end example With tedious algebra, you can derive the above formulae yourself by substituting the transform for S into H(S)=S-x for a zero at x or H(S)=1/(S-x) for a pole at x, and converting the result into the form: @example H(Z)=g prod(Z-Xi)/prod(Z-Xj) @end example Please note that a pole and a zero at the same place exactly cancel. This is significant since the bilinear transform creates numerous extra poles and zeros, most of which cancel. Those which do not cancel have a "fill-in" effect, extending the shorter of the sets to have the same number of as the longer of the sets of poles and zeros (or at least split the difference in the case of the band pass filter). There may be other opportunistic cancellations but I will not check for them. Also note that any pole on the unit circle or beyond will result in an unstable filter. Because of cancellation, this will only happen if the number of poles is smaller than the number of zeros. The analytic design methods all yield more poles than zeros, so this will not be a problem. References: Proakis & Manolakis (1992). Digital Signal Processing. New York: Macmillan Publishing Company. @end deftypefn @c IIR Filter Design buttap @c ----------------------------------------- @subsection buttap @cindex buttap @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} buttap (@var{n}) Design lowpass analog Butterworth filter. This function exists for @sc{matlab} compatibility only, and is equivalent to @code{butter (@var{n}, 1, "s")}. @xseealso{butter} @end deftypefn @c IIR Filter Design butter @c ----------------------------------------- @subsection butter @cindex butter @deftypefn {Function File} {[@var{b}, @var{a}] =} butter (@var{n}, @var{wc}) @deftypefnx {Function File} {[@var{b}, @var{a}] =} butter (@var{n}, @var{wc}, @var{filter_type}) @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} butter (@dots{}) @deftypefnx {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} butter (@dots{}) @deftypefnx {Function File} {[@dots{}] =} butter (@dots{}, "s") Generate a Butterworth filter. Default is a discrete space (Z) filter. The cutoff frequency, @var{wc} should be specified in radians for analog filters. For digital filters, it must be a value between zero and one. For bandpass filters, @var{wc} is a two-element vector with @code{w(1) < w(2)}. The filter type must be one of @qcode{"low"}, @qcode{"high"}, @qcode{"bandpass"}, or @qcode{"stop"}. The default is @qcode{"low"} if @var{wc} is a scalar and @qcode{"bandpass"} if @var{wc} is a two-element vector. If the final input argument is @qcode{"s"} design an analog Laplace space filter. Low pass filter with cutoff @code{pi*Wc} radians: @example [b, a] = butter (n, Wc) @end example High pass filter with cutoff @code{pi*Wc} radians: @example [b, a] = butter (n, Wc, "high") @end example Band pass filter with edges @code{pi*Wl} and @code{pi*Wh} radians: @example [b, a] = butter (n, [Wl, Wh]) @end example Band reject filter with edges @code{pi*Wl} and @code{pi*Wh} radians: @example [b, a] = butter (n, [Wl, Wh], "stop") @end example Return filter as zero-pole-gain rather than coefficients of the numerator and denominator polynomials: @example [z, p, g] = butter (@dots{}) @end example Return a Laplace space filter, @var{Wc} can be larger than 1: @example [@dots{}] = butter (@dots{}, "s") @end example Return state-space matrices: @example [a, b, c, d] = butter (@dots{}) @end example References: Proakis & Manolakis (1992). Digital Signal Processing. New York: Macmillan Publishing Company. @end deftypefn @c IIR Filter Design buttord @c ----------------------------------------- @subsection buttord @cindex buttord @deftypefn {Function File} {@var{n} =} buttord (@var{wp}, @var{ws}, @var{rp}, @var{rs}) @deftypefnx {Function File} {@var{n} =} buttord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}) @deftypefnx {Function File} {@var{n} =} buttord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}, "s") @deftypefnx {Function File} {[@var{n}, @var{wc_p}] =} buttord (@dots{}) @deftypefnx {Function File} {[@var{n}, @var{wc_p}, @var{wc_s}] =} buttord (@dots{}) Compute the minimum filter order of a Butterworth filter with the desired response characteristics. The filter frequency band edges are specified by the passband frequency @var{wp} and stopband frequency @var{ws}. Frequencies are normalized to the Nyquist frequency in the range [0,1]. @var{rp} is the allowable passband ripple measured in decibels, and @var{rs} is the minimum attenuation in the stop band, also in decibels. The output arguments @var{n} and @var{wc_p} (or @var{n} and @var{wc_n}) can be given as inputs to @code{butter}. Using @var{wc_p} makes the filter characteristic touch at least one pass band corner and using @var{wc_s} makes the characteristic touch at least one stop band corner. If @var{wp} and @var{ws} are scalars, then @var{wp} is the passband cutoff frequency and @var{ws} is the stopband edge frequency. If @var{ws} is greater than @var{wp}, the filter is a low-pass filter. If @var{wp} is greater than @var{ws}, the filter is a high-pass filter. If @var{wp} and @var{ws} are vectors of length 2, then @var{wp} defines the passband interval and @var{ws} defines the stopband interval. If @var{wp} is contained within @var{ws} (@var{ws1} < @var{wp1} < @var{wp2} < @var{ws2}), the filter is a band-pass filter. If @var{ws} is contained within @var{wp} (@var{wp1} < @var{ws1} < @var{ws2} < @var{wp2}), the filter is a band-stop or band-reject filter. If the optional argument @code{"s"} is given, the minimum order for an analog elliptic filter is computed. All frequencies @var{wp} and @var{ws} are specified in radians per second. Theory: For Low pass filters, |H(W)|^2 = 1/[1+(W/Wc)^(2N)] = 10^(-R/10). With some algebra, you can solve simultaneously for Wc and N given Ws,Rs and Wp,Rp. Rounding N to the next greater integer, one can recalculate the allowable range for Wc (filter caracteristic touching the pass band edge or the stop band edge). For other types of filter, before making the above calculation, the requirements must be transformed to LP requirements. After calculation, Wc must be transformed back to original filter type. @xseealso{butter, cheb1ord, cheb2ord, ellipord} @end deftypefn @c IIR Filter Design cheb @c ----------------------------------------- @subsection cheb @cindex cheb @deftypefn {Function File} {} cheb (@var{n}, @var{x}) Returns the value of the nth-order Chebyshev polynomial calculated at the point x. The Chebyshev polynomials are defined by the equations: @example @group / cos(n acos(x), |x| <= 1 Tn(x) = | \ cosh(n acosh(x), |x| > 1 @end group @end example If x is a vector, the output is a vector of the same size, where each element is calculated as y(i) = Tn(x(i)). @end deftypefn @c IIR Filter Design cheb1ap @c ----------------------------------------- @subsection cheb1ap @cindex cheb1ap @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} cheb1ap (@var{n}, @var{Rp}) Design lowpass analog Chebyshev type I filter. This function exists for @sc{matlab} compatibility only, and is equivalent to @code{cheby1 (@var{n}, @var{Rp}, 1, "s")}. @xseealso{cheby1} @end deftypefn @c IIR Filter Design cheb1ord @c ----------------------------------------- @subsection cheb1ord @cindex cheb1ord @deftypefn {Function File} {@var{n} =} cheb1ord (@var{wp}, @var{ws}, @var{rp}, @var{rs}) @deftypefnx {Function File} {@var{n} =} cheb1ord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}) @deftypefnx {Function File} {@var{n} =} cheb1ord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}, "s") @deftypefnx {Function File} {[@var{n}, @var{wc}] =} cheb1ord (@dots{}) @deftypefnx {Function File} {[@var{n}, @var{wc_p}, @var{wc_s}] =} cheb1ord (@dots{}) Compute the minimum filter order of a Chebyshev type I filter with the desired response characteristics. The filter frequency band edges are specified by the passband frequency @var{wp} and stopband frequency @var{ws}. Frequencies are normalized to the Nyquist frequency in the range [0,1]. @var{rp} is the allowable passband ripple measured in decibels, and @var{rs} is the minimum attenuation in the stop band, also in decibels. The output arguments @var{n} and @var{wc_p} (or @var{n} and @var{wc_s}) can be given as inputs to @code{cheby1}. Using @var{wc_p} makes the filter characteristic touch at least one pass band corner and using @var{wc_s} makes the characteristic touch at least one stop band corner. If @var{wp} and @var{ws} are scalars, then @var{wp} is the passband cutoff frequency and @var{ws} is the stopband edge frequency. If @var{ws} is greater than @var{wp}, the filter is a low-pass filter. If @var{wp} is greater than @var{ws}, the filter is a high-pass filter. If @var{wp} and @var{ws} are vectors of length 2, then @var{wp} defines the passband interval and @var{ws} defines the stopband interval. If @var{wp} is contained within @var{ws} (@var{ws1} < @var{wp1} < @var{wp2} < @var{ws2}), the filter is a band-pass filter. If @var{ws} is contained within @var{wp} (@var{wp1} < @var{ws1} < @var{ws2} < @var{wp2}), the filter is a band-stop or band-reject filter. If the optional argument @code{"s"} is given, the minimum order for an analog elliptic filter is computed. All frequencies @var{wp} and @var{ws} are specified in radians per second. @xseealso{buttord, cheby1, cheb2ord, ellipord} @end deftypefn @c IIR Filter Design cheb2ap @c ----------------------------------------- @subsection cheb2ap @cindex cheb2ap @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} cheb2ap (@var{n}, @var{Rs}) Design lowpass analog Chebyshev type II filter. This function exists for @sc{matlab} compatibility only, and is equivalent to @code{cheby2 (@var{n}, @var{Rs}, 1, "s")}. Demo @example demo cheb2ap @end example @xseealso{cheby2} @end deftypefn @c IIR Filter Design cheb2ord @c ----------------------------------------- @subsection cheb2ord @cindex cheb2ord @deftypefn {Function File} {@var{n} =} cheb2ord (@var{wp}, @var{ws}, @var{rp}, @var{rs}) @deftypefnx {Function File} {@var{n} =} cheb2ord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}) @deftypefnx {Function File} {@var{n} =} cheb2ord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}, "s") @deftypefnx {Function File} {[@var{n}, @var{wc_s}] =} cheb2ord (@dots{}) @deftypefnx {Function File} {[@var{n}, @var{wc_s}, @var{wc_p}] =} cheb2ord (@dots{}) Compute the minimum filter order of a Chebyshev type II filter with the desired response characteristics. The filter frequency band edges are specified by the passband frequency @var{wp} and stopband frequency @var{ws}. Frequencies are normalized to the Nyquist frequency in the range [0,1]. @var{rp} is the allowable passband ripple measured in decibels, and @var{rs} is the minimum attenuation in the stop band, also in decibels. The output arguments @var{n} and @var{wc_p} (or @var{n} and @var{wc_s}) can be given as inputs to @code{cheby2}. Using @var{wc_p} makes the filter characteristic touch at least one pass band corner and using @var{wc_s} makes the characteristic touch at least one stop band corner. If @var{wp} and @var{ws} are scalars, then @var{wp} is the passband cutoff frequency and @var{ws} is the stopband edge frequency. If @var{ws} is greater than @var{wp}, the filter is a low-pass filter. If @var{wp} is greater than @var{ws}, the filter is a high-pass filter. If @var{wp} and @var{ws} are vectors of length 2, then @var{wp} defines the passband interval and @var{ws} defines the stopband interval. If @var{wp} is contained within @var{ws} (@var{ws1} < @var{wp1} < @var{wp2} < @var{ws2}), the filter is a band-pass filter. If @var{ws} is contained within @var{wp} (@var{wp1} < @var{ws1} < @var{ws2} < @var{wp2}), the filter is a band-stop or band-reject filter. If the optional argument @code{"s"} is given, the minimum order for an analog elliptic filter is computed. All frequencies @var{wp} and @var{ws} are specified in radians per second. @xseealso{buttord, cheb1ord, cheby2, ellipord} @end deftypefn @c IIR Filter Design cheby1 @c ----------------------------------------- @subsection cheby1 @cindex cheby1 @deftypefn {Function File} {[@var{b}, @var{a}] =} cheby1 (@var{n}, @var{rp}, @var{w}) @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby1 (@var{n}, @var{rp}, @var{w}, "high") @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby1 (@var{n}, @var{rp}, [@var{wl}, @var{wh}]) @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby1 (@var{n}, @var{rp}, [@var{wl}, @var{wh}], "stop") @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} cheby1 (@dots{}) @deftypefnx {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} cheby1 (@dots{}) @deftypefnx {Function File} {[@dots{}] =} cheby1 (@dots{}, "s") Generate a Chebyshev type I filter with @var{rp} dB of passband ripple. [b, a] = cheby1(n, Rp, Wc) low pass filter with cutoff pi*Wc radians [b, a] = cheby1(n, Rp, Wc, 'high') high pass filter with cutoff pi*Wc radians [b, a] = cheby1(n, Rp, [Wl, Wh]) band pass filter with edges pi*Wl and pi*Wh radians [b, a] = cheby1(n, Rp, [Wl, Wh], 'stop') band reject filter with edges pi*Wl and pi*Wh radians [z, p, g] = cheby1(...) return filter as zero-pole-gain rather than coefficients of the numerator and denominator polynomials. [...] = cheby1(...,'s') return a Laplace space filter, W can be larger than 1. [a,b,c,d] = cheby1(...) return state-space matrices References: Parks & Burrus (1987). Digital Filter Design. New York: John Wiley & Sons, Inc. @end deftypefn @c IIR Filter Design cheby2 @c ----------------------------------------- @subsection cheby2 @cindex cheby2 @deftypefn {Function File} {[@var{b}, @var{a}] =} cheby2 (@var{n}, @var{rs}, @var{wc}) @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby2 (@var{n}, @var{rs}, @var{wc}, "high") @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby2 (@var{n}, @var{rs}, [@var{wl}, @var{wh}]) @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby2 (@var{n}, @var{rs}, [@var{wl}, @var{wh}], "stop") @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} cheby2 (@dots{}) @deftypefnx {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} cheby2 (@dots{}) @deftypefnx {Function File} {[@dots{}] =} cheby2 (@dots{}, "s") Generate a Chebyshev type II filter with @var{rs} dB of stopband attenuation. [b, a] = cheby2(n, Rs, Wc) low pass filter with cutoff pi*Wc radians [b, a] = cheby2(n, Rs, Wc, 'high') high pass filter with cutoff pi*Wc radians [b, a] = cheby2(n, Rs, [Wl, Wh]) band pass filter with edges pi*Wl and pi*Wh radians [b, a] = cheby2(n, Rs, [Wl, Wh], 'stop') band reject filter with edges pi*Wl and pi*Wh radians [z, p, g] = cheby2(...) return filter as zero-pole-gain rather than coefficients of the numerator and denominator polynomials. [...] = cheby2(...,'s') return a Laplace space filter, W can be larger than 1. [a,b,c,d] = cheby2(...) return state-space matrices References: Parks & Burrus (1987). Digital Filter Design. New York: John Wiley & Sons, Inc. @end deftypefn @c IIR Filter Design ellip @c ----------------------------------------- @subsection ellip @cindex ellip @deftypefn {Function File} {[@var{b}, @var{a}] =} ellip (@var{n}, @var{rp}, @var{rs}, @var{wp}) @deftypefnx {Function File} {[@var{b}, @var{a}] =} ellip (@var{n}, @var{rp}, @var{rs}, @var{wp}, "high") @deftypefnx {Function File} {[@var{b}, @var{a}] =} ellip (@var{n}, @var{rp}, @var{rs}, @var{[wl}, @var{wh}]) @deftypefnx {Function File} {[@var{b}, @var{a}] =} ellip (@var{n}, @var{rp}, @var{rs}, @var{[wl}, @var{wh}], "stop") @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} ellip (@dots{}) @deftypefnx {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} ellip (@dots{}) @deftypefnx {Function File} {[@dots{}] =} ellip (@dots{}, "s") Generate an elliptic or Cauer filter with @var{rp} dB of passband ripple and @var{rs} dB of stopband attenuation. [b,a] = ellip(n, Rp, Rs, Wp) low pass filter with order n, cutoff pi*Wp radians, Rp decibels of ripple in the passband and a stopband Rs decibels down. [b,a] = ellip(n, Rp, Rs, Wp, 'high') high pass filter with cutoff pi*Wp... [b,a] = ellip(n, Rp, Rs, [Wl, Wh]) band pass filter with band pass edges pi*Wl and pi*Wh ... [b,a] = ellip(n, Rp, Rs, [Wl, Wh], 'stop') band reject filter with edges pi*Wl and pi*Wh, ... [z,p,g] = ellip(...) return filter as zero-pole-gain. [...] = ellip(...,'s') return a Laplace space filter, W can be larger than 1. [a,b,c,d] = ellip(...) return state-space matrices References: - Oppenheim, Alan V., Discrete Time Signal Processing, Hardcover, 1999. - Parente Ribeiro, E., Notas de aula da disciplina TE498 - Processamento Digital de Sinais, UFPR, 2001/2002. @end deftypefn @c IIR Filter Design ellipap @c ----------------------------------------- @subsection ellipap @cindex ellipap @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} ellipap (@var{n}, @var{Rp}, @var{Rs}) Design lowpass analog elliptic filter. This function exists for @sc{matlab} compatibility only, and is equivalent to @code{ellip (@var{n}, @var{Rp}, @var{Rs}, 1, "s")}. @xseealso{ellip} @end deftypefn @c IIR Filter Design ellipord @c ----------------------------------------- @subsection ellipord @cindex ellipord @deftypefn {Function File} {@var{n} =} ellipord (@var{wp}, @var{ws}, @var{rp}, @var{rs}) @deftypefnx {Function File} {@var{n} =} ellipord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}) @deftypefnx {Function File} {@var{n} =} ellipord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}, "s") @deftypefnx {Function File} {[@var{n}, @var{wc}] =} ellipord (@dots{}) Compute the minimum filter order of an elliptic filter with the desired response characteristics. The filter frequency band edges are specified by the passband frequency @var{wp} and stopband frequency @var{ws}. Frequencies are normalized to the Nyquist frequency in the range [0,1]. @var{rp} is the allowable passband ripple measured in decibels, and @var{rs} is the minimum attenuation in the stop band, also in decibels. The output arguments @var{n} and @var{wc} can be given as inputs to @code{ellip}. If @var{wp} and @var{ws} are scalars, then @var{wp} is the passband cutoff frequency and @var{ws} is the stopband edge frequency. If @var{ws} is greater than @var{wp}, the filter is a low-pass filter. If @var{wp} is greater than @var{ws}, the filter is a high-pass filter. If @var{wp} and @var{ws} are vectors of length 2, then @var{wp} defines the passband interval and @var{ws} defines the stopband interval. If @var{wp} is contained within @var{ws} (@var{ws1} < @var{wp1} < @var{wp2} < @var{ws2}), the filter is a band-pass filter. If @var{ws} is contained within @var{wp} (@var{wp1} < @var{ws1} < @var{ws2} < @var{wp2}), the filter is a band-stop or band-reject filter. If the optional argument @code{"s"} is given, the minimum order for an analog elliptic filter is computed. All frequencies @var{wp} and @var{ws} are specified in radians per second. Reference: Lamar, Marcus Vinicius, @cite{Notas de aula da disciplina TE 456 - Circuitos Analogicos II}, UFPR, 2001/2002. @xseealso{buttord, cheb1ord, cheb2ord, ellip} @end deftypefn @c IIR Filter Design firpm @c ----------------------------------------- @subsection firpm @cindex firpm @deftypefn {Loadable Function} {@var{b} =} firpm (@var{n}, @var{f}, @var{a}) @deftypefnx {Loadable Function} {@var{b} =} firpm (@var{n}, @var{f}, @@@var{respFn}) @deftypefnx {Loadable Function} {@var{b} =} firpm (@var{n}, @var{f}, @{@@@var{respFn}, @dots{}@}) @deftypefnx {Loadable Function} {@var{b} =} firpm (@dots{}, @var{w}) @deftypefnx {Loadable Function} {@var{b} =} firpm (@dots{}, @var{class}) @deftypefnx {Loadable Function} {@var{b} =} firpm (@dots{}, @{@var{accuracy, @dots{}@}}) @deftypefnx {Loadable Function} {[@var{b}, @var{minimax}] =} firpm (@dots{}) @deftypefnx {Loadable Function} {[@var{b}, @var{minimax}, @var{res}] =} firpm (@dots{}) @cindex signal processing Designs a linear-phase FIR filter according to given specifications and the `minimax' criterion. The method (per McClellan et al.@footnote{ J. H. McClellan, T. W. Parks and L. R. Rabiner, `A Computer Program for Designing Optimum FIR Linear Phase Digital Filters', IEEE Trans.@: Audio Electroacoust., vol.@: AU-21, 1973, pp.@: 506--525.}) uses successive approximation to minimize the maximum weighted error between the desired and actual frequency response of the filter. Such filters are variably described as being `minimax', `equiripple', or `optimal (in the Chebyshev sense)'. @heading Arguments @table @var @item @dots{} Where shown as the first argument to @code{firpm}, indicates that any previously-indicated list of arguments may substitute for the ellipsis. @item n A positive integer giving the filter order. @item f A vector of real-numbers, increasing in the range [0,1], giving the frequencies of the left and right edges of each band for which a specific amplitude response is desired: [l1 r1 l2 r2 @dots{}]. 1 represents the Nyquist-frequency. Transition-bands are defined implicitly as the regions between or outside the given bands. @item a A vector of real-numbers giving the desired amplitude response. An amplitude value is given either for each band edge: [a(l1) a(r1) a(l2) a(r2) @dots{}], or for each band: [a1 a2 @dots{}]. In the former case, in-band amplitude is determined by linear interpolation between the given band-edge values. 1 represents unity-gain, 0 represents infinite attenuation, and @minus{}1 represents a phase change of pi radians. Note that amplitude response is necessarily zero at @var{f}=0 for type III and IV filters, and at @var{f}=1 for type II and III filters. @item @@respFn A handle to a `response function' that supplies the desired amplitude response and error-weighting. This, unlike @var{a} above, allows the response to be arbitrary (subject to the note above). @qcode{firpm} invokes the response function according to the following syntax: @example @var{ag} = @qcode{respFn} (@var{n},@var{f},@var{g},@var{w}, @dots{}) [@var{ag} @var{wg}] = @qcode{respFn} (@var{n},@var{f},@var{g},@var{w}, @dots{}) @var{symmetry} = @qcode{respFn} ("defaults", @{@var{n},@var{f},@var{g},@var{w}, @dots{}@}) @end example where: @itemize @item @var{n} and @var{f} are as given to @qcode{firpm}. @item @var{w} is as given to @qcode{firpm}, or ones if not given. @item @var{ag} and @var{wg} are the desired amplitude and weighting functions evaluated at each frequency in vector @var{g} (which are frequencies within the non-transition bands of @var{f}). Returning @var{ag} alone gives uniform weighting. @item @var{symmetry} is either @qcode{"even"} or @qcode{"odd"}; this provides an alternative to using the @var{class} values @qcode{"symmetric"} and @qcode{"antisymmetric"}. @item Per the ellipses shown here and above, when @@@var{respFn} is given contained in a cell-array, any additionally contained values are appended to the @var{respFn} invocation argument-list. @end itemize @item w When used in conjunction with @var{a}, @var{w} is a vector of positive real-numbers giving error-weightings to be applied at each given band-edge [w(l1) w(r1) w(l2) w(r2) @dots{}], or for each band [w1 w2 @dots{}]. In the former case, in-band weighting is determined by linear interpolation between the given band-edge values. A higher relative error weighting yields a lower relative error. When used in conjunction with @@@var{respFn}, @var{w} is a vector (constrained as above) that is passed through to @var{respFn}. @item class A string, which may be abbreviated, giving the filter-class: @itemize @item @qcode{"symmetric"} (the default) for type I or II filters, @item @qcode{"antisymmetric"} (or @qcode{"hilbert"}) for standard type III or IV filters, @item @qcode{"differentiator"} for type III or IV filters with inverted phase and with error-weighting (further to @var{w}) of 2/f applied in the pass-band(s). @end itemize @item accuracy, @dots{} Up to three properties contained within a cell-array: @var{accuracy}, @var{persistence}, @var{robustness}, that respectively control how close the computed filter will be to the ideal minimax solution, the number of computation iterations over which the required accuracy will be sought, and the precision of certain internal processing. Each can each be set to a small positive number (typically @leq{}3), to increase the relevant item; this may increase computation time, but the need to do so should be rare. A value of 0 can be used to leave an item unchanged. Alternatively, setting @var{accuracy} @geq{}16 emulates @sc{matlab}'s @var{lgrid} argument. @end table @heading Results If a problem occurs during the computation, a diagnostic message will normally be displayed. If this happens, adjusting @var{accuracy}, @var{persistence}, or @var{robustness} may provide the solution. Some filters however, may not be realizable due to machine-precision limitations. If a filter can be computed, returned values are as follows: @table @var @item b A length @var{N}+1 row-vector containing the computed filter coefficients. @item minimax The absolute value of the minimized, maximum weighted error, or this number negated if the required accuracy could not be achieved. @item res A structure of data relating to the filter computation and a partial response-analysis of the resultant filter; fields are vectors: @quotation @multitable @columnfractions .125 .6 @item @code{fgrid} @tab Analysis frequencies per @var{f}. @item @code{des} @tab Desired amplitude response. @item @code{wt} @tab Error weighting. @item @code{H} @tab Complex frequency response. @item @code{error} @tab Desired minus actual amplitude response. @item @code{iextr} @tab Indices of local peaks in @code{error}. @item @code{fextr} @tab Frequencies of local peaks in @code{error}. @end multitable @end quotation @end table Using @var{res} is not recommended because it can be slow to compute and, since the analysis excludes transition-bands, any `anomalies'@footnote{ Tapio Saram@"aki, `Finite impulse response filter design', Chapter 4 in `Handbook for Digital Signal Processing', edited by S. K. Mitra and J. F. Kaiser, John Wiley and Sons, New York, 1993, pp.@: 155--277. (@url{http://www.cs.tut.fi/~ts/Mitra_Kaiser.pdf})} therein are not easy to discern. In general, @code{freqz} suffices to check that the response of the computed filter is satisfactory. @heading Examples @example @group # Low-pass with frequencies in Hz: Fs = 96000; Fn = Fs/2; # Sampling & Nyquist frequencies. b = firpm (50, [0 20000 28000 48000] / Fn, [1 0]); @end group @end example @example @group # Type IV high-pass: b = firpm (31, [0 0.5 0.7 1], [0 1], "antisym"); @end group @end example @example @group # Inverse-sinc (arbitrary response): b = firpm (20, [0 0.5 0.9 1], @@(n,f,g) ... deal ((g<=f(2))./sinc (g), (g>=f(3))*9+1)); @end group @end example @example @group # Band-pass with filter-response check: freqz (firpm (40, [0 3 4 6 8 10]/10, [0 1 0])) @end group @end example Further examples can be found in the @code{firpm} and @code{firpmord} demonstration scripts. @heading Compatibility Given invalid filter specifications, Octave emits an error and does not produce a filter; @sc{matlab} in such circumstances may still produce filter coefficients. Unlike with @sc{matlab}, with Octave @var{minimax} can be negative; for compatibility, take the absolute value. @xseealso{firpmord} @end deftypefn @c IIR Filter Design firpmord @c ----------------------------------------- @subsection firpmord @cindex firpmord @deftypefn {Function File} {[@var{n}, @var{Fout}, @var{a}, @var{w}] =} firpmord (@var{f}, @var{a}, @var{d}) @deftypefnx {Function File} {[@var{n}, @var{Fout}, @var{a}, @var{w}] =} firpmord (@var{f}, @var{a}, @var{d}, @var{fs}) @deftypefnx {Function File} {@var{c} =} firpmord (@var{f}, @var{a}, @var{d}, "cell") @deftypefnx {Function File} {@var{c} =} firpmord (@var{f}, @var{a}, @var{d}, @var{fs}, "cell") @cindex signal processing Estimate the filter-order needed for @code{firpm} to design a type-I or type-II linear-phase FIR filter according to the given specifications. @heading Arguments @table @var @item f A vector of real-numbers, increasing in the range (0, @var{fs}/2), giving the frequencies of the left and right edges of each band for which a specific amplitude response is desired (omitting 0 and @var{fs}/2, which are implied): [r1 l2 r2 @dots{}]. Transition-bands are defined implicitly as the regions between the given bands. @item a A vector of real-numbers giving the ideal amplitude response. An amplitude value is given for each band specified by @var{f}: [a1 a2 @dots{}]. 1 represents unity-gain, 0 represents infinite attenuation, and @minus{}1 represents a phase change of pi radians. @item d A vector of positive real-numbers giving the maximum allowable linear deviation from the amplitudes given in @var{a}, thus constraining the actual amplitude response (where defined by @var{f}) to be within @var{a} +/@minus{} @var{d}. Note that, though related, @var{d} does not equate to @code{firpm}'s @var{w} argument. @item fs The sampling-frequency, which defaults to 2. @end table @heading Usage The function returns the estimated filter-order, together with the other design specification values, in one of two forms suitable for use with @code{firpm}. By default, multiple return values are used; alternatively, by giving @qcode{"cell"} (or @qcode{"c"}) as the last argument to @code{firpmord}, the returned values are contained within a cell-array that can, if desired, be passed directly to @code{firpm}. The following examples illustrate the use of both mechanisms, as well as aspects of @code{firpmord} usage in general: @example @group # Low-pass; frequencies in kHz: [n f a w] = firpmord ([2.5 3], [1 0], [0.01 db2mag(-60)], 8); b = firpm (n, f, a, w); @end group @end example @example @group # Band-pass: c = firpmord ([3 4 8 9], [0 1 0], [1e-3 1e-2 1e-3], 20, "cell"); b = firpm (c@{:@}); @end group @end example @example @group # High-pass: b = firpm (firpmord ([6.4 8]/16, [0 1], [1e-4 0.01], "c")@{:@}); @end group @end example In cases where elements of @var{d} follow a repeating pattern (e.g.@: all the elements are equal, or elements corresponding to pass-bands are equal and elements corresponding to stop-bands are equal), only as many elements as are needed to establish the pattern need be given. For example, the following @code{firpmord} invocation pairs are equivalent: @example @group # Low-pass: firpmord ([0.4 0.5], [0 1], [db2mag(-72) db2mag(-72)]); firpmord ([0.4 0.5], [0 1], [db2mag(-72)]); @end group @end example @example @group # Multi-band-pass: ds = db2mag(-80); dp = 0.01; firpmord ([1 2 3 4 5 6 7 8]/10, [0 1 0 1 0], [ds dp ds dp ds]); firpmord ([1 2 3 4 5 6 7 8]/10, [0 1 0 1 0], [ds dp]); @end group @end example @heading Notes The estimation algorithm used is per Ichige et al.@footnote{ K. Ichige, M. Iwaki, algorithm and R. Ishii, `Accurate Estimation of Minimum Filter Length for Optimum FIR Digital Filters', IEEE Transactions on Circuits and Systems, Vol.@: 47, No.@: 10, 2000, pp.@: 1008--1017} Accuracy tends to decrease as the number of bands increases. Even with two bands (i.e.@: high-pass or low-pass), the algorithm may under- or over-estimate. See the @code{firpmord} demonstrations for some examples. In order to precisely determine the minimum order needed for a particular design, @code{firpmord} could be used to seed an algorithm iterating invocations of @code{firpm} (as exemplified in demonstration number five). @heading Related documentation @xseealso{firpm, kaiserord} @end deftypefn @c IIR Filter Design iirlp2mb @c IIR Filter Design impinvar @c ----------------------------------------- @subsection impinvar @cindex impinvar @deftypefn {Function File} {[@var{b_out}, @var{a_out}] =} impinvar (@var{b}, @var{a}, @var{fs}, @var{tol}) @deftypefnx {Function File} {[@var{b_out}, @var{a_out}] =} impinvar (@var{b}, @var{a}, @var{fs}) @deftypefnx {Function File} {[@var{b_out}, @var{a_out}] =} impinvar (@var{b}, @var{a}) Converts analog filter with coefficients @var{b} and @var{a} to digital, conserving impulse response. If @var{fs} is not specified, or is an empty vector, it defaults to 1Hz. If @var{tol} is not specified, it defaults to 0.0001 (0.1%) This function does the inverse of impinvar so that the following example should restore the original values of @var{a} and @var{b}. @command{invimpinvar} implements the reverse of this function. @example [b, a] = impinvar (b, a); [b, a] = invimpinvar (b, a); @end example Reference: Thomas J. Cavicchi (1996) ``Impulse invariance and multiple-order poles''. IEEE transactions on signal processing, Vol 44 (9): 2344--2347 @xseealso{bilinear, invimpinvar} @end deftypefn @c IIR Filter Design invimpinvar @c ----------------------------------------- @subsection invimpinvar @cindex invimpinvar @deftypefn {Function File} {[@var{b_out}, @var{a_out}] =} invimpinvar (@var{b}, @var{a}, @var{fs}, @var{tol}) @deftypefnx {Function File} {[@var{b_out}, @var{a_out}] =} invimpinvar (@var{b}, @var{a}, @var{fs}) @deftypefnx {Function File} {[@var{b_out}, @var{a_out}] =} invimpinvar (@var{b}, @var{a}) Converts digital filter with coefficients @var{b} and @var{a} to analog, conserving impulse response. This function does the inverse of impinvar so that the following example should restore the original values of @var{a} and @var{b}. @example [b, a] = impinvar (b, a); [b, a] = invimpinvar (b, a); @end example If @var{fs} is not specified, or is an empty vector, it defaults to 1Hz. If @var{tol} is not specified, it defaults to 0.0001 (0.1%) Reference: Thomas J. Cavicchi (1996) ``Impulse invariance and multiple-order poles''. IEEE transactions on signal processing, Vol 40 (9): 2344--2347 @xseealso{bilinear, impinvar} @end deftypefn @c IIR Filter Design ncauer @c ----------------------------------------- @subsection ncauer @cindex ncauer @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} cauer(@var{Rp}, @var{Rs}, @var{n}) Analog prototype for Cauer filter. @table @asis @item Rp Passband ripple @item Rs Stopband ripple @item n Desired order @item z complex vector of zeros for the model. @item p complex vector of poles for the model. @item g gain value. @end table References: - Serra, Celso Penteado, Teoria e Projeto de Filtros, Campinas: CARTGRAF, 1983. - Lamar, Marcus Vinicius, Notas de aula da disciplina TE 456 - Circuitos Analogicos II, UFPR, 2001/2002. @end deftypefn @c IIR Filter Design pei_tseng_notch @c ----------------------------------------- @subsection pei_tseng_notch @cindex pei_tseng_notch @deftypefn {Function File} {[@var{b}, @var{a}] =} pei_tseng_notch (@var{frequencies}, @var{bandwidths}) Return coefficients for an IIR notch-filter with one or more filter frequencies and according (very narrow) bandwidths to be used with @code{filter} or @code{filtfilt}. The filter construction is based on an allpass which performs a reversal of phase at the filter frequencies. Thus, the mean of the phase-distorted and the original signal has the respective frequencies removed. See the demo for an illustration. Original source: Pei, Soo-Chang, and Chien-Cheng Tseng "IIR Multiple Notch Filter Design Based on Allpass Filter" 1996 IEEE Tencon doi: 10.1109/TENCON.1996.608814) @end deftypefn @c IIR Filter Design sftrans @c ----------------------------------------- @subsection sftrans @cindex sftrans @deftypefn {Function File} {[@var{Sz}, @var{Sp}, @var{Sg}] =} sftrans (@var{Sz}, @var{Sp}, @var{Sg}, @var{W}, @var{stop}) Transform band edges of a generic lowpass filter (cutoff at W=1) represented in splane zero-pole-gain form. W is the edge of the target filter (or edges if band pass or band stop). Stop is true for high pass and band stop filters or false for low pass and band pass filters. Filter edges are specified in radians, from 0 to pi (the nyquist frequency). Theory: Given a low pass filter represented by poles and zeros in the splane, you can convert it to a low pass, high pass, band pass or band stop by transforming each of the poles and zeros individually. The following table summarizes the transformation: @example Transform Zero at x Pole at x ---------------- ------------------------- ------------------------ Low Pass zero: Fc x/C pole: Fc x/C S -> C S/Fc gain: C/Fc gain: Fc/C ---------------- ------------------------- ------------------------ High Pass zero: Fc C/x pole: Fc C/x S -> C Fc/S pole: 0 zero: 0 gain: -x gain: -1/x ---------------- ------------------------- ------------------------ Band Pass zero: b +- sqrt(b^2-FhFl) pole: b +- sqrt(b^2-FhFl) S^2+FhFl pole: 0 zero: 0 S -> C -------- gain: C/(Fh-Fl) gain: (Fh-Fl)/C S(Fh-Fl) b=x/C (Fh-Fl)/2 b=x/C (Fh-Fl)/2 ---------------- ------------------------- ------------------------ Band Stop zero: b +- sqrt(b^2-FhFl) pole: b +- sqrt(b^2-FhFl) S(Fh-Fl) pole: +-sqrt(-FhFl) zero: +-sqrt(-FhFl) S -> C -------- gain: -x gain: -1/x S^2+FhFl b=C/x (Fh-Fl)/2 b=C/x (Fh-Fl)/2 ---------------- ------------------------- ------------------------ Bilinear zero: (2+xT)/(2-xT) pole: (2+xT)/(2-xT) 2 z-1 pole: -1 zero: -1 S -> - --- gain: (2-xT)/T gain: (2-xT)/T T z+1 ---------------- ------------------------- ------------------------ @end example where C is the cutoff frequency of the initial lowpass filter, Fc is the edge of the target low/high pass filter and [Fl,Fh] are the edges of the target band pass/stop filter. With abundant tedious algebra, you can derive the above formulae yourself by substituting the transform for S into H(S)=S-x for a zero at x or H(S)=1/(S-x) for a pole at x, and converting the result into the form: @example H(S)=g prod(S-Xi)/prod(S-Xj) @end example The transforms are from the references. The actual pole-zero-gain changes I derived myself. Please note that a pole and a zero at the same place exactly cancel. This is significant for High Pass, Band Pass and Band Stop filters which create numerous extra poles and zeros, most of which cancel. Those which do not cancel have a "fill-in" effect, extending the shorter of the sets to have the same number of as the longer of the sets of poles and zeros (or at least split the difference in the case of the band pass filter). There may be other opportunistic cancellations but I will not check for them. Also note that any pole on the unit circle or beyond will result in an unstable filter. Because of cancellation, this will only happen if the number of poles is smaller than the number of zeros and the filter is high pass or band pass. The analytic design methods all yield more poles than zeros, so this will not be a problem. References: Proakis & Manolakis (1992). Digital Signal Processing. New York: Macmillan Publishing Company. @end deftypefn @c --------------------------------------------------- @node FIR Filter Design @section FIR Filter Design @cindex FIR Filter Design @c FIR Filter Design cl2bp @c ----------------------------------------- @subsection cl2bp @cindex cl2bp @deftypefn {Loadable Function} {@var{h} =} cl2bp (@var{m}, @var{w1}, @var{w2}, @var{up}, @var{lo}) @deftypefnx {Loadable Function} {@var{h} =} cl2bp (@var{m}, @var{w1}, @var{w2}, @var{up}, @var{lo}, @var{gridsize}) Constrained L2 bandpass FIR filter design. This is a fast implementation of the algorithm cited below. Compared to @dfn{remez}, it offers implicit specification of transition bands, a higher likelihood of convergence, and an error criterion combining features of both L2 and Chebyshev approaches. Inputs: @table @var @item m degree of cosine polynomial, i.e. the number of output coefficients will be @var{m}*2+1 @item w1 @itemx w2 bandpass filter cutoffs in the range 0 <= @var{w1} < @var{w2} <= pi, where pi is the Nyquist frequency @item up vector of 3 upper bounds for [stopband1, passband, stopband2] @item lo vector of 3 lower bounds for [stopband1, passband, stopband2] @item gridsize search grid size; larger values may improve accuracy, but greatly increase calculation time. @end table Output: A vector of @var{m}*2+1 FIR coefficients, or an empty value if the solver failed to converge. Example: @example @code{h = cl2bp(30, 0.3*pi, 0.6*pi, [0.02, 1.02, 0.02], [-0.02, 0.98, -0.02], 2^11);} @end example Original Paper: I. W. Selesnick, M. Lang, and C. S. Burrus. A modified algorithm for constrained least square design of multiband FIR filters without specified transition bands. IEEE Trans. on Signal Processing, 46(2):497-501, February 1998. @end deftypefn @xseealso{remez} @c FIR Filter Design fir1 @c ----------------------------------------- @subsection fir1 @cindex fir1 @deftypefn {Function File} {@var{b} =} fir1 (@var{n}, @var{w}) @deftypefnx {Function File} {@var{b} =} fir1 (@var{n}, @var{w}, @var{type}) @deftypefnx {Function File} {@var{b} =} fir1 (@var{n}, @var{w}, @var{type}, @var{window}) @deftypefnx {Function File} {@var{b} =} fir1 (@var{n}, @var{w}, @var{type}, @var{window}, @var{noscale}) Produce an order @var{n} FIR filter with the given frequency cutoff @var{w}, returning the @var{n}+1 filter coefficients in @var{b}. If @var{w} is a scalar, it specifies the frequency cutoff for a lowpass or highpass filter. If @var{w} is a two-element vector, the two values specify the edges of a bandpass or bandstop filter. If @var{w} is an N-element vector, each value specifies a band edge of a multiband pass/stop filter. The filter @var{type} can be specified with one of the following strings: "low", "high", "stop", "pass", "bandpass", "DC-0", or "DC-1". The default is "low" is @var{w} is a scalar, "pass" if @var{w} is a pair, or "DC-0" if @var{w} is a vector with more than 2 elements. An optional shaping @var{window} can be given as a vector with length @var{n}+1. If not specified, a Hamming window of length @var{n}+1 is used. With the option "noscale", the filter coefficients are not normalized. The default is to normalize the filter such that the magnitude response of the center of the first passband is 1. To apply the filter, use the return vector @var{b} with the @code{filter} function, for example @code{y = filter (b, 1, x)}. Examples: @example freqz (fir1 (40, 0.3)); freqz (fir1 (15, [0.2, 0.5], "stop")); # note the zero-crossing at 0.1 freqz (fir1 (15, [0.2, 0.5], "stop", "noscale")); @end example @xseealso{filter, fir2} @end deftypefn @c FIR Filter Design fir2 @c ----------------------------------------- @subsection fir2 @cindex fir2 @deftypefn {Function File} {@var{b} =} fir2 (@var{n}, @var{f}, @var{m}) @deftypefnx {Function File} {@var{b} =} fir2 (@var{n}, @var{f}, @var{m}, @var{grid_n}) @deftypefnx {Function File} {@var{b} =} fir2 (@var{n}, @var{f}, @var{m}, @var{grid_n}, @var{ramp_n}) @deftypefnx {Function File} {@var{b} =} fir2 (@var{n}, @var{f}, @var{m}, @var{grid_n}, @var{ramp_n}, @var{window}) Produce an order @var{n} FIR filter with arbitrary frequency response @var{m} over frequency bands @var{f}, returning the @var{n}+1 filter coefficients in @var{b}. The vector @var{f} specifies the frequency band edges of the filter response and @var{m} specifies the magnitude response at each frequency. The vector @var{f} must be nondecreasing over the range [0,1], and the first and last elements must be 0 and 1, respectively. A discontinuous jump in the frequency response can be specified by duplicating a band edge in @var{f} with different values in @var{m}. The resolution over which the frequency response is evaluated can be controlled with the @var{grid_n} argument. The default is 512 or the next larger power of 2 greater than the filter length. The band transition width for discontinuities can be controlled with the @var{ramp_n} argument. The default is @var{grid_n}/25. Larger values will result in wider band transitions but better stopband rejection. An optional shaping @var{window} can be given as a vector with length @var{n}+1. If not specified, a Hamming window of length @var{n}+1 is used. To apply the filter, use the return vector @var{b} with the @code{filter} function, for example @code{y = filter (b, 1, x)}. Example: @example f = [0, 0.3, 0.3, 0.6, 0.6, 1]; m = [0, 0, 1, 1/2, 0, 0]; [h, w] = freqz (fir2 (100, f, m)); plot (f, m, ";target response;", w/pi, abs (h), ";filter response;"); @end example @xseealso{filter, fir1} @end deftypefn @c FIR Filter Design firls @c ----------------------------------------- @subsection firls @cindex firls @deftypefn {Function File} {@var{b} =} firls (@var{n}, @var{f}, @var{a}) @deftypefnx {Function File} {@var{b} =} firls (@var{n}, @var{f}, @var{a}, @var{w}) FIR filter design using least squares method. Returns a length @var{n}+1 linear phase filter such that the integral of the weighted mean squared error in the specified bands is minimized. The vector @var{f} specifies the frequencies of the band edges, normalized so that half the sample frequency is equal to 1. Each band is specified by two frequencies, to the vector must have an even length. The vector @var{a} specifies the amplitude of the desired response at each band edge. The optional argument @var{w} is a weighting function that contains one value for each band that weights the mean squared error in that band. @var{a} must be the same length as @var{f}, and @var{w} must be half the length of @var{f}. @var{n} must be even. If given an odd value, @code{firls} increments it by 1. The least squares optimization algorithm for computing FIR filter coefficients is derived in detail in: I. Selesnick, "Linear-Phase FIR Filter Design by Least Squares," http://cnx.org/content/m10577 @end deftypefn @c FIR Filter Design kaiserord @c ----------------------------------------- @subsection kaiserord @cindex kaiserord @deftypefn {Function File} {[@var{n}, @var{Wn}, @var{beta}, @var{ftype}] =} kaiserord (@var{f}, @var{m}, @var{dev}) @deftypefnx {Function File} {[@dots{}] =} kaiserord (@var{f}, @var{m}, @var{dev}, @var{fs}) Return the parameters needed to produce a filter of the desired specification from a Kaiser window. The vector @var{f} contains pairs of frequency band edges in the range [0,1]. The vector @var{m} specifies the magnitude response for each band. The values of @var{m} must be zero for all stop bands and must have the same magnitude for all pass bands. The deviation of the filter @var{dev} can be specified as a scalar or a vector of the same length as @var{m}. The optional sampling rate @var{fs} can be used to indicate that @var{f} is in Hz in the range [0,@var{fs}/2]. The returned value @var{n} is the required order of the filter (the length of the filter minus 1). The vector @var{Wn} contains the band edges of the filter suitable for passing to @code{fir1}. The value @var{beta} is the parameter of the Kaiser window of length @var{n}+1 to shape the filter. The string @var{ftype} contains the type of filter to specify to @code{fir1}. The Kaiser window parameters n and beta are computed from the relation between ripple (A=-20*log10(dev)) and transition width (dw in radians) discovered empirically by Kaiser: @example @group / 0.1102(A-8.7) A > 50 beta = | 0.5842(A-21)^0.4 + 0.07886(A-21) 21 <= A <= 50 \ 0.0 A < 21 n = (A-8)/(2.285 dw) @end group @end example Example: @example @group [n, w, beta, ftype] = kaiserord ([1000, 1200], [1, 0], [0.05, 0.05], 11025); b = fir1 (n, w, kaiser (n+1, beta), ftype, "noscale"); freqz (b, 1, [], 11025); @end group @end example @xseealso{fir1, kaiser} @end deftypefn @c FIR Filter Design qp_kaiser @c ----------------------------------------- @subsection qp_kaiser @cindex qp_kaiser @deftypefn {Function File} {} qp_kaiser (@var{nb}, @var{at}) @deftypefnx {Function File} {} qp_kaiser (@var{nb}, @var{at}, @var{linear}) Computes a finite impulse response (FIR) filter for use with a quasi-perfect reconstruction polyphase-network filter bank. This version utilizes a Kaiser window to shape the frequency response of the designed filter. Tha number nb of bands and the desired attenuation at in the stop-band are given as parameters. The Kaiser window is multiplied by the ideal impulse response h(n)=a.sinc(a.n) and converted to its minimum-phase version by means of a Hilbert transform. By using a third non-null argument, the minimum-phase calculation is omitted at all. @end deftypefn @c FIR Filter Design remez @c ----------------------------------------- @subsection remez @cindex remez @deftypefn {Loadable Function} {@var{b} =} remez (@var{n}, @var{f}, @var{a}) @deftypefnx {Loadable Function} {@var{b} =} remez (@var{n}, @var{f}, @var{a}, @var{w}) @deftypefnx {Loadable Function} {@var{b} =} remez (@var{n}, @var{f}, @var{a}, @var{w}, @var{ftype}) @deftypefnx {Loadable Function} {@var{b} =} remez (@var{n}, @var{f}, @var{a}, @var{w}, @var{ftype}, @var{griddensity}) Parks-McClellan optimal FIR filter design. @table @var @item n gives the filter order, where the generated filter length taps is n+1 @item f gives frequency at the band edges [b1 e1 b2 e2 b3 e3 @dots{}] @item a gives amplitude at the band edges [a(b1) a(e1) a(b2) a(e2) @dots{}] @item w gives weighting applied to each band @item ftype is "bandpass", "hilbert" or "differentiator" @item griddensity determines how accurately the filter will be constructed. The minimum value is 16, but higher numbers are slower to compute. @end table Frequency is in the range (0, 1), with 1 being the Nyquist frequency. @end deftypefn @c FIR Filter Design sgolay @c ----------------------------------------- @subsection sgolay @cindex sgolay @deftypefn {Function File} {@var{f} =} sgolay (@var{p}, @var{n}) @deftypefnx {Function File} {@var{f} =} sgolay (@var{p}, @var{n}, @var{m}) @deftypefnx {Function File} {@var{f} =} sgolay (@var{p}, @var{n}, @var{m}, @var{ts}) Computes the filter coefficients for all Savitzsky-Golay smoothing filters of order p for length n (odd). m can be used in order to get directly the mth derivative. In this case, ts is a scaling factor. The early rows of F smooth based on future values and later rows smooth based on past values, with the middle row using half future and half past. In particular, you can use row i to estimate x(k) based on the i-1 preceding values and the n-i following values of x values as y(k) = F(i,:) * x(k-i+1:k+n-i). Normally, you would apply the first (n-1)/2 rows to the first k points of the vector, the last k rows to the last k points of the vector and middle row to the remainder, but for example if you were running on a realtime system where you wanted to smooth based on the all the data collected up to the current time, with a lag of five samples, you could apply just the filter on row n-5 to your window of length n each time you added a new sample. Reference: Numerical recipes in C. p 650 @xseealso{sgolayfilt} @end deftypefn @c --------------------------------------------------- @node Transforms @section Transforms @cindex Transforms @c Transforms bitrevorder @c ----------------------------------------- @subsection bitrevorder @cindex bitrevorder @deftypefn {Function File} {@var{y} =} bitrevorder (@var{x}) @deftypefnx {Function File} {[@var{y} @var{i}] =} bitrevorder (@var{x}) Reorder the elements of the vector @var{x} in bit-reversed order. Equivalent to calling @code{digitrevorder (@var{x}, 2)}. @xseealso{digitrevorder, fft, ifft} @end deftypefn @c Transforms cceps @c ----------------------------------------- @subsection cceps @cindex cceps @deftypefn {Function File} {} cceps (@var{x}) @deftypefnx {Function File} {} cceps (@var{x}, @var{correct}) Return the complex cepstrum of the vector @var{x}. If the optional argument @var{correct} has the value 1, a correction method is applied. The default is not to do this. @end deftypefn @c Transforms cplxreal @c ----------------------------------------- @subsection cplxreal @cindex cplxreal @deftypefn {Function File} {[@var{zc}, @var{zr}] =} cplxreal (@var{z}) @deftypefnx {Function File} {[@var{zc}, @var{zr}] =} cplxreal (@var{z}, @var{tol}) @deftypefnx {Function File} {[@var{zc}, @var{zr}] =} cplxreal (@var{z}, @var{tol}, @var{dim}) Sort the numbers @var{z} into complex-conjugate-valued and real-valued elements. The positive imaginary complex numbers of each complex conjugate pair are returned in @var{zc} and the real numbers are returned in @var{zr}. @var{tol} is a weighting factor in the range [0, 1) which determines the tolerance of the matching. The default value is @code{100 * eps} and the resulting tolerance for a given complex pair is @code{@var{tol} * abs (@var{z}(i)))}. By default the complex pairs are sorted along the first non-singleton dimension of @var{z}. If @var{dim} is specified, then the complex pairs are sorted along this dimension. Signal an error if some complex numbers could not be paired. Signal an error if all complex numbers are not exact conjugates (to within @var{tol}). Note that there is no defined order for pairs with identical real parts but differing imaginary parts. @xseealso{cplxpair} @end deftypefn @c Transforms czt @c ----------------------------------------- @subsection czt @cindex czt @deftypefn {Function File} {} czt (@var{x}) @deftypefnx {Function File} {} czt (@var{x}, @var{m}) @deftypefnx {Function File} {} czt (@var{x}, @var{m}, @var{w}) @deftypefnx {Function File} {} czt (@var{x}, @var{m}, @var{w}, @var{a}) Chirp z-transform. Compute the frequency response starting at a and stepping by w for m steps. a is a point in the complex plane, and w is the ratio between points in each step (i.e., radius increases exponentially, and angle increases linearly). To evaluate the frequency response for the range f1 to f2 in a signal with sampling frequency Fs, use the following: @example @group m = 32; ## number of points desired w = exp(-j*2*pi*(f2-f1)/((m-1)*Fs)); ## freq. step of f2-f1/m a = exp(j*2*pi*f1/Fs); ## starting at frequency f1 y = czt(x, m, w, a); @end group @end example If you don't specify them, then the parameters default to a Fourier transform: m=length(x), w=exp(-j*2*pi/m), a=1 If x is a matrix, the transform will be performed column-by-column. @end deftypefn @c Transforms dct @c ----------------------------------------- @subsection dct @cindex dct @deftypefn {Function File} {} dct (@var{x}) @deftypefnx {Function File} {} dct (@var{x}, @var{n}) Compute the discrete cosine transform of @var{x}. If @var{n} is given, then @var{x} is padded or trimmed to length @var{n} before computing the transform. If @var{x} is a matrix, compute the transform along the columns of the the matrix. The transform is faster if @var{x} is real-valued and has even length. The discrete cosine transform @var{x} can be defined as follows: @example @group N-1 X[k] = w(k) sum x[n] cos (pi (2n+1) k / 2N ), k = 0, ..., N-1 n=0 @end group @end example with w(0) = sqrt(1/N) and w(k) = sqrt(2/N), k = 1, ..., N-1. There are other definitions with different scaling of X[k], but this form is common in image processing. @xseealso{idct, dct2, idct2, dctmtx} @end deftypefn @c Transforms dct2 @c ----------------------------------------- @subsection dct2 @cindex dct2 @deftypefn {Function File} {} dct2 (@var{x}) @deftypefnx {Function File} {} dct2 (@var{x}, @var{m}, @var{n}) @deftypefnx {Function File} {} dct2 (@var{x}, [@var{m}, @var{n}]) Compute the 2-D discrete cosine transform of matrix @var{x}. If @var{m} and @var{n} are specified, the input is padded or trimmed to the desired size. @xseealso{dct, idct, idct2} @end deftypefn @c Transforms dctmtx @c ----------------------------------------- @subsection dctmtx @cindex dctmtx @deftypefn {Function File} {} dctmtx (@var{n}) Return the DCT transformation matrix of size @var{n}-by-@var{n}. If A is an @var{n}-by-@var{n} matrix, then the following are true: @example @group T*A == dct(A), T'*A == idct(A) T*A*T' == dct2(A), T'*A*T == idct2(A) @end group @end example A DCT transformation matrix is useful for doing things like jpeg image compression, in which an 8x8 DCT matrix is applied to non-overlapping blocks throughout an image and only a subblock on the top left of each block is kept. During restoration, the remainder of the block is filled with zeros and the inverse transform is applied to the block. @xseealso{dct, idct, dct2, idct2} @end deftypefn @c Transforms dftmtx @c ----------------------------------------- @subsection dftmtx @cindex dftmtx @deftypefn {Function File} {@var{d} =} dftmtx (@var{n}) Compute the @var{n}-by-@var{n} Fourier transformation matrix. This is the matrix @var{d} such that the Fourier transform of a column vector of length @var{n} is given by @code{dftmtx(@var{n}) * @var{x}} and the inverse Fourier transform is given by @code{inv(dftmtx(@var{n})) * @var{x}}. In general this is less efficient than calling the @code{fft} and @code{ifft} functions directly. @xseealso{fft, ifft} @end deftypefn @c Transforms digitrevorder @c ----------------------------------------- @subsection digitrevorder @cindex digitrevorder @deftypefn {Function File} {@var{y} =} digitrevorder (@var{x}, @var{r}) @deftypefnx {Function File} {[@var{y}, @var{i}] =} digitrevorder (@var{x}, @var{r}) Reorder the elements of the vector @var{x} in digit-reversed order. The elements of @var{x} are converted to radix @var{r} and reversed. The reordered indices of the elements of @var{x} are returned in @var{i}. @xseealso{bitrevorder, fft, ifft} @end deftypefn @c Transforms dst @c ----------------------------------------- @subsection dst @cindex dst @deftypefn {Function File} {@var{y} =} dst (@var{x}) @deftypefnx {Function File} {@var{y} =} dst (@var{x}, @var{n}) Computes the type I discrete sine transform of @var{x}. If @var{n} is given, then @var{x} is padded or trimmed to length @var{n} before computing the transform. If @var{x} is a matrix, compute the transform along the columns of the the matrix. The discrete sine transform X of x can be defined as follows: @verbatim N X[k] = sum x[n] sin (pi n k / (N+1) ), k = 1, ..., N n=1 @end verbatim @xseealso{idst} @end deftypefn @c Transforms dwt @c ----------------------------------------- @subsection dwt @cindex dwt @deftypefn {Function File} {[@var{u}, @var{v}] =} dwt (@var{x}, @var{wname}) @deftypefnx {Function File} {[@var{u}, @var{v}] =} dwt (@var{x}, @var{Hp}, @var{Gp}) @deftypefnx {Function File} {[@var{u}, @var{v}] =} dwt (@var{x}, @var{Hp}, @var{Gp}, @dots{}) Discrete wavelet transform (1D). @strong{Inputs} @table @var @item x Signal vector. @item wname Wavelet name. @item Hp Coefficients of low-pass decomposition @acronym{FIR} filter. @item Gp Coefficients of high-pass decomposition @acronym{FIR} filter. @end table @strong{Outputs} @table @var @item u Signal vector of average, approximation. @item v Signal vector of difference, detail. @end table @end deftypefn @c Transforms fht @c ----------------------------------------- @subsection fht @cindex fht @deftypefn {Function File} {@var{m} =} fht (@var{d}) @deftypefnx {Function File} {@var{m} =} fht (@var{d}, @var{n}) @deftypefnx {Function File} {@var{m} =} fht (@var{d}, @var{n}, @var{dim}) Calculate the Fast Hartley Transform of real input @var{d}. If @var{d} is a matrix, the Hartley transform is calculated along the columns by default. The options @var{n} and @var{dim} are similar to the options of FFT function. The forward and inverse Hartley transforms are the same (except for a scale factor of 1/N for the inverse Hartley transform), but implemented using different functions. The definition of the forward hartley transform for vector d, @math{ m[K] = \sum_{i=0}^{N-1} d[i]*(cos[K*2*pi*i/N] + sin[K*2*pi*i/N]), for 0 <= K < N. m[K] = \sum_{i=0}^{N-1} d[i]*CAS[K*i], for 0 <= K < N. } @example fht(1:4) @end example @xseealso{ifht, fft} @end deftypefn @c Transforms fwht @c ----------------------------------------- @subsection fwht @cindex fwht @deftypefn {Function File} {} fwht (@var{x}) @deftypefnx {Function File} {} fwht (@var{x}, @var{n}) @deftypefnx {Function File} {} fwht (@var{x}, @var{n}, @var{order}) Compute the Walsh-Hadamard transform of @var{x} using the Fast Walsh-Hadamard Transform (FWHT) algorithm. If the input is a matrix, the FWHT is calculated along the columns of @var{x}. The number of elements of @var{x} must be a power of 2; if not, the input will be extended and filled with zeros. If a second argument is given, the input is truncated or extended to have length @var{n}. The third argument specifies the @var{order} in which the returned Walsh-Hadamard transform coefficients should be arranged. The @var{order} may be any of the following strings: @table @asis @item "sequency" The coefficients are returned in sequency order. This is the default if @var{order} is not given. @item "hadamard" The coefficients are returned in Hadamard order. @item "dyadic" The coefficients are returned in Gray code order. @end table @xseealso{ifwht} @end deftypefn @c Transforms hilbert @c ----------------------------------------- @subsection hilbert @cindex hilbert @deftypefn {Function File} {@var{h} =} hilbert (@var{f}, @var{N}, @var{dim}) Analytic extension of real valued signal. @code{@var{h} = hilbert (@var{f})} computes the extension of the real valued signal @var{f} to an analytic signal. If @var{f} is a matrix, the transformation is applied to each column. For N-D arrays, the transformation is applied to the first non-singleton dimension. @code{real (@var{h})} contains the original signal @var{f}. @code{imag (@var{h})} contains the Hilbert transform of @var{f}. @code{hilbert (@var{f}, @var{N})} does the same using a length @var{N} Hilbert transform. The result will also have length @var{N}. @code{hilbert (@var{f}, [], @var{dim})} or @code{hilbert (@var{f}, @var{N}, @var{dim})} does the same along dimension @var{dim}. @end deftypefn @c Transforms idct @c ----------------------------------------- @subsection idct @cindex idct @deftypefn {Function File} {@var{y} =} idct (@var{x}) @deftypefnx {Function File} {@var{y} =} idct (@var{x}, @var{n}) Compute the inverse discrete cosine transform of @var{x}. If @var{n} is given, then @var{x} is padded or trimmed to length @var{n} before computing the transform. If @var{x} is a matrix, compute the transform along the columns of the the matrix. The transform is faster if @var{x} is real-valued and even length. The inverse discrete cosine transform @var{x} can be defined as follows: @example N-1 x[n] = sum w(k) X[k] cos (pi (2n+1) k / 2N ), n = 0, ..., N-1 k=0 @end example with w(0) = sqrt(1/N) and w(k) = sqrt(2/N), k = 1, ..., N-1 @xseealso{dct, dct2, idct2, dctmtx} @end deftypefn @c Transforms idct2 @c ----------------------------------------- @subsection idct2 @cindex idct2 @deftypefn {Function File} {@var{y} =} idct2 (@var{x}) @deftypefnx {Function File} {@var{y} =} idct2 (@var{x}, @var{m}, @var{n}) @deftypefnx {Function File} {@var{y} =} idct2 (@var{x}, [@var{m}, @var{n}]) Compute the inverse 2-D discrete cosine transform of matrix @var{x}. If @var{m} and @var{n} are specified, the input is either padded or truncated to have @var{m} rows and @var{n} columns. @end deftypefn @c Transforms idst @c ----------------------------------------- @subsection idst @cindex idst @deftypefn {Function File} {@var{y} =} idst (@var{x}) @deftypefnx {Function File} {@var{y} =} idst (@var{x}, @var{n}) Computes the inverse type I discrete sine transform of @var{y}. If @var{n} is given, then @var{y} is padded or trimmed to length @var{n} before computing the transform. If @var{y} is a matrix, compute the transform along the columns of the the matrix. @xseealso{dst} @end deftypefn @c Transforms ifht @c ----------------------------------------- @subsection ifht @cindex ifht @deftypefn {Function File} {@var{m} =} ifht (@var{d}, @var{n}, @var{dim}) Calculate the inverse Fast Hartley Transform of real input @var{d}. If @var{d} is a matrix, the inverse Hartley transform is calculated along the columns by default. The options @var{n} and @var{dim} are similar to the options of FFT function. The forward and inverse Hartley transforms are the same (except for a scale factor of 1/N for the inverse hartley transform), but implemented using different functions. The definition of the forward hartley transform for vector d, @math{ m[K] = 1/N \sum_{i=0}^{N-1} d[i]*(cos[K*2*pi*i/N] + sin[K*2*pi*i/N]), for 0 <= K < N. m[K] = 1/N \sum_{i=0}^{N-1} d[i]*CAS[K*i], for 0 <= K < N. } @example ifht(1:4) @end example @xseealso{fht, fft} @end deftypefn @c Transforms ifwht @c ----------------------------------------- @subsection ifwht @cindex ifwht @deftypefn {Function File} {} ifwht (@var{x}) @deftypefnx {Function File} {} ifwht (@var{x}, @var{n}) @deftypefnx {Function File} {} ifwht (@var{x}, @var{n}, @var{order}) Compute the inverse Walsh-Hadamard transform of @var{x} using the Fast Walsh-Hadamard Transform (FWHT) algorithm. If the input is a matrix, the inverse FWHT is calculated along the columns of @var{x}. The number of elements of @var{x} must be a power of 2; if not, the input will be extended and filled with zeros. If a second argument is given, the input is truncated or extended to have length @var{n}. The third argument specifies the @var{order} in which the returned inverse Walsh-Hadamard transform coefficients should be arranged. The @var{order} may be any of the following strings: @table @asis @item "sequency" The coefficients are returned in sequency order. This is the default if @var{order} is not given. @item "hadamard" The coefficients are returned in Hadamard order. @item "dyadic" The coefficients are returned in Gray code order. @end table @xseealso{fwht} @end deftypefn @c Transforms rceps @c ----------------------------------------- @subsection rceps @cindex rceps @deftypefn {Function File} {[@var{y}, @var{ym}] =} rceps (@var{x}) Return the cepstrum of the signal @var{x}. If @var{x} is a matrix, return the cepstrum of each column. If called with two output arguments, the minimum phase reconstruction of the signal @var{x} is returned in @var{ym}. For example: @example @group f0 = 70; Fs = 10000; # 100 Hz fundamental, 10kHz sampling rate a = poly (0.985 * exp (1i * pi * [0.1, -0.1, 0.3, -0.3])); # two formants s = 0.005 * randn (1024, 1); # Noise excitation signal s(1:Fs/f0:length(s)) = 1; # Impulse glottal wave x = filter (1, a, s); # Speech signal [y, ym] = rceps (x .* hanning (1024)); @end group @end example Reference: @cite{Programs for Digital Signal Processing}, IEEE Press, John Wiley & Sons, New York, 1979. @end deftypefn @c --------------------------------------------------- @node Power Spectrum Analysis @section Power Spectrum Analysis @cindex Power Spectrum Analysis @c Power Spectrum Analysis __power @c ----------------------------------------- @subsection __power @cindex __power @deftypefn {Function File} {[@var{P}, @var{w}] =} __power (@var{b}, @var{a}) @deftypefnx {Function File} {[@dots{}] =} __power (@var{b}, @var{a}, @var{nfft}) @deftypefnx {Function File} {[@dots{}] =} __power (@var{b}, @var{a}, @var{nfft}, @var{Fs}) @deftypefnx {Function File} {[@dots{}] =} __power (@var{b}, @var{a}, @var{nfft}, @var{Fs}, @var{range}) @deftypefnx {Function File} {[@dots{}] =} __power (@var{b}, @var{a}, @var{nfft}, @var{Fs}, @var{range}, @var{units}) @deftypefnx {Function File} {} __power (@dots{}) Plot the power spectrum of the given ARMA model. b, a: filter coefficients (b=numerator, a=denominator) nfft is number of points at which to sample the power spectrum Fs is the sampling frequency of x range is 'half' (default) or 'whole' units is 'squared' or 'db' (default) range and units may be specified any time after the filter, in either order Returns P, the magnitude vector, and w, the frequencies at which it is sampled. If there are no return values requested, then plot the power spectrum and don't return anything. @end deftypefn @c Power Spectrum Analysis ar_psd @c ----------------------------------------- @subsection ar_psd @cindex ar_psd @deftypefn {Function File} {} ar_psd (@var{a}, @var{v}) @deftypefnx {Function File} {} ar_psd (@var{a}, @var{v}, @var{freq}) @deftypefnx {Function File} {} ar_psd (@var{a}, @var{v}, @var{freq}, @var{Fs}) @deftypefnx {Function File} {} ar_psd (@dots{}, @var{range}) @deftypefnx {Function File} {} ar_psd (@dots{}, @var{method}) @deftypefnx {Function File} {} ar_psd (@dots{}, @var{plottype}) @deftypefnx {Function File} {[@var{psd}, @var{f_out}] =} ar_psd (@dots{}) Calculate the power spectrum of the autoregressive model @example @group M x(n) = sqrt(v).e(n) + SUM a(k).x(n-k) k=1 @end group @end example where @math{x(n)} is the output of the model and @math{e(n)} is white noise. This function is intended for use with @code{[a, v, k] = arburg (x, poles, criterion)} which use the Burg (1968) method to calculate a "maximum entropy" autoregressive model of @var{x}. If the @var{freq} argument is a vector (of frequencies) the spectrum is calculated using the polynomial method and the @var{method} argument is ignored. For scalar @var{freq}, an integer power of 2, or @var{method} = "FFT", causes the spectrum to be calculated by FFT. Otherwise, the spectrum is calculated as a polynomial. It may be computationally more efficient to use the FFT method if length of the model is not much smaller than the number of frequency values. The spectrum is scaled so that spectral energy (area under spectrum) is the same as the time-domain energy (mean square of the signal). ARGUMENTS: All but the first two arguments are optional and may be empty. @itemize @item @var{a} list of M=(order+1) autoregressive model coefficients. The first element of "ar_coeffs" is the zero-lag coefficient, which always has a value of 1. @item @var{v} square of the moving-average coefficient of the AR model. @item @var{freq} frequencies at which power spectral density is calculated, or a scalar indicating the number of uniformly distributed frequency values at which spectral density is calculated. (default = 256) @item @var{Fs} sampling frequency (Hertz) (default=1) @end itemize CONTROL-STRING ARGUMENTS -- each of these arguments is a character string. Control-string arguments can be in any order after the other arguments. Range: 'half', 'onesided' : frequency range of the spectrum is from zero up to but not including sample_f/2. Power from negative frequencies is added to the positive side of the spectrum. 'whole', 'twosided' : frequency range of the spectrum is -sample_f/2 to sample_f/2, with negative frequencies stored in "wrap around" order after the positive frequencies; e.g. frequencies for a 10-point 'twosided' spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 'shift', 'centerdc' : same as 'whole' but with the first half of the spectrum swapped with second half to put the zero-frequency value in the middle. (See "help fftshift". If "freq" is vector, 'shift' is ignored. If model coefficients "ar_coeffs" are real, the default range is 'half', otherwise default range is 'whole'. Method: 'fft': use FFT to calculate power spectrum. 'poly': calculate power spectrum as a polynomial of 1/z N.B. this argument is ignored if the "freq" argument is a vector. The default is 'poly' unless the "freq" argument is an integer power of 2. Plot type: 'plot', 'semilogx', 'semilogy', 'loglog', 'squared' or 'db': specifies the type of plot. The default is 'plot', which means linear-linear axes. 'squared' is the same as 'plot'. 'dB' plots "10*log10(psd)". This argument is ignored and a spectrum is not plotted if the caller requires a returned value. RETURNED VALUES: If returned values are not required by the caller, the spectrum is plotted and nothing is returned. @itemize @item @var{psd} estimate of power-spectral density @item @var{f_out} frequency values @end itemize REFERENCE [1] Equation 2.28 from Steven M. Kay and Stanley Lawrence Marple Jr.: "Spectrum analysis -- a modern perspective", Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981 @end deftypefn @c Power Spectrum Analysis cohere @c ----------------------------------------- @subsection cohere @cindex cohere @deftypefn {Function File} {[@var{Pxx}, @var{freq}]} = cohere(@var{x},@var{y},@var{Nfft},@var{Fs},@var{window},@var{overlap},@var{range},@var{plot_type},@var{detrend}) Estimate (mean square) coherence of signals "x" and "y". Use the Welch (1967) periodogram/FFT method. Compatible with Matlab R11 cohere and earlier. See "help pwelch" for description of arguments, hints and references --- especially hint (7) for Matlab R11 defaults. @end deftypefn @c Power Spectrum Analysis cpsd @c ----------------------------------------- @subsection cpsd @cindex cpsd @deftypefn {Function File} {[@var{Pxx}, @var{freq}] =} cpsd (@var{x}, @var{y}) @deftypefnx {Function File} {[@dots{}] =} cpsd (@var{x}, @var{y}, @var{window}) @deftypefnx {Function File} {[@dots{}] =} cpsd (@var{x}, @var{y}, @var{window}, @var{overlap}) @deftypefnx {Function File} {[@dots{}] =} cpsd (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}) @deftypefnx {Function File} {[@dots{}] =} cpsd (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}) @deftypefnx {Function File} {[@dots{}] =} cpsd (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}, @var{range}) @deftypefnx {Function File} {} cpsd (@dots{}) Estimate cross power spectrum of data @var{x} and @var{y} by the Welch (1967) periodogram/FFT method. @xseealso{pwelch} @end deftypefn @c Power Spectrum Analysis csd @c ----------------------------------------- @subsection csd @cindex csd @deftypefn {Function File} {[@var{Pxx},@var{freq}]} = csd(@var{x}, @var{y}, @var{Nfft}, @var{Fs}, @var{window}, @var{overlap}, @var{range}, @var{plot_type}, @var{detrend}) Estimate cross power spectrum of data "x" and "y" by the Welch (1967) periodogram/FFT method. Compatible with Matlab R11 csd and earlier. See "help pwelch" for description of arguments, hints and references --- especially hint (7) for Matlab R11 defaults. @end deftypefn @c Power Spectrum Analysis db2pow @c ----------------------------------------- @subsection db2pow @cindex db2pow @deftypefn {Function File} {} db2pow (@var{x}) Convert decibels (dB) to power. The power of @var{x} is defined as @tex $p = 10^{x/10}$. @end tex @ifnottex @var{p} = @code{10 ^ (x/10)}. @end ifnottex If @var{x} is a vector, matrix, or N-dimensional array, the power is computed over the elements of @var{x}. Example: @example @group db2pow ([-10, 0, 10]) @result{} 0.1000 1.0000 10.0000 @end group @end example @xseealso{pow2db} @end deftypefn @c Power Spectrum Analysis mscohere @c ----------------------------------------- @subsection mscohere @cindex mscohere @deftypefn {Function File} {[@var{Pxx}, @var{freq}] =} mscohere (@var{x}, @var{y}) @deftypefnx {Function File} {[@dots{}] =} mscohere (@var{x}, @var{y}, @var{window}) @deftypefnx {Function File} {[@dots{}] =} mscohere (@var{x}, @var{y}, @var{window}, @var{overlap}) @deftypefnx {Function File} {[@dots{}] =} mscohere (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}) @deftypefnx {Function File} {[@dots{}] =} mscohere (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}) @deftypefnx {Function File} {[@dots{}] =} mscohere (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}, @var{range}) @deftypefnx {Function File} {} mscohere (@dots{}) Estimate (mean square) coherence of signals @var{x} and @var{y}. Use the Welch (1967) periodogram/FFT method. @xseealso{pwelch} @end deftypefn @c Power Spectrum Analysis pburg @c ----------------------------------------- @subsection pburg @cindex pburg @deftypefn {Function File} {[@var{psd},@var{f_out}] =} pburg(@var{x}, @var{poles}, @var{freq}, @var{Fs}, @var{range}, @var{method}, @var{plot_type}, @var{criterion}) Calculate Burg maximum-entropy power spectral density. The functions "arburg" and "ar_psd" do all the work. See "help arburg" and "help ar_psd" for further details. ARGUMENTS: All but the first two arguments are optional and may be empty. @table @asis @item x [vector] sampled data @item poles [integer scalar] required number of poles of the AR model @item freq [real vector] frequencies at which power spectral density is calculated. [integer scalar] number of uniformly distributed frequency values at which spectral density is calculated. [default=256] @item Fs [real scalar] sampling frequency (Hertz) [default=1] @end table CONTROL-STRING ARGUMENTS -- each of these arguments is a character string. Control-string arguments can be in any order after the other arguments. @table @asis @item range 'half', 'onesided' : frequency range of the spectrum is from zero up to but not including sample_f/2. Power from negative frequencies is added to the positive side of the spectrum. 'whole', 'twosided' : frequency range of the spectrum is -sample_f/2 to sample_f/2, with negative frequencies stored in "wrap around" order after the positive frequencies; e.g. frequencies for a 10-point 'twosided' spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 'shift', 'centerdc' : same as 'whole' but with the first half of the spectrum swapped with second half to put the zero-frequency value in the middle. (See "help fftshift". If "freq" is vector, 'shift' is ignored. If model coefficients "ar_coeffs" are real, the default range is 'half', otherwise default range is 'whole'. @item method 'fft': use FFT to calculate power spectral density. 'poly': calculate spectral density as a polynomial of 1/z N.B. this argument is ignored if the "freq" argument is a vector. The default is 'poly' unless the "freq" argument is an integer power of 2. @item plot_type 'plot', 'semilogx', 'semilogy', 'loglog', 'squared' or 'db': specifies the type of plot. The default is 'plot', which means linear-linear axes. 'squared' is the same as 'plot'. 'dB' plots "10*log10(psd)". This argument is ignored and a spectrum is not plotted if the caller requires a returned value. @item criterion [optional string arg] model-selection criterion. Limits the number of poles so that spurious poles are not added when the whitened data has no more information in it (see Kay & Marple, 1981). Recognized values are 'AKICc' -- approximate corrected Kullback information criterion (recommended), 'KIC' -- Kullback information criterion 'AICc' -- corrected Akaike information criterion 'AIC' -- Akaike information criterion 'FPE' -- final prediction error" criterion The default is to NOT use a model-selection criterion @end table RETURNED VALUES: If return values are not required by the caller, the spectrum is plotted and nothing is returned. @table @asis @item psd [real vector] power-spectral density estimate @item f_out [real vector] frequency values @end table HINTS This function is a wrapper for arburg and ar_psd. See "help arburg", "help ar_psd". @end deftypefn @c Power Spectrum Analysis pow2db @c ----------------------------------------- @subsection pow2db @cindex pow2db @deftypefn {Function File} {} pow2db (@var{x}) Convert power to decibels (dB). The decibel value of @var{x} is defined as @tex $d = 10 * \log_{10} (x)$. @end tex @ifnottex @var{d} = @code{10 * log10 (x)}. @end ifnottex If @var{x} is a vector, matrix, or N-dimensional array, the decibel value is computed over the elements of @var{x}. Examples: @example @group pow2db ([0, 10, 100]) @result{} -Inf 10 20 @end group @end example @xseealso{db2pow} @end deftypefn @c Power Spectrum Analysis pwelch @c ----------------------------------------- @subsection pwelch @cindex pwelch @deftypefn {Function File} {[@var{spectra},@var{freq}] =} pwelch(@var{x}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}, @var{range}, @var{plot_type}, @var{detrend}, @var{sloppy}) Estimate power spectral density of data "x" by the Welch (1967) periodogram/FFT method. All arguments except "x" are optional. The data is divided into segments. If "window" is a vector, each segment has the same length as "window" and is multiplied by "window" before (optional) zero-padding and calculation of its periodogram. If "window" is a scalar, each segment has a length of "window" and a Hamming window is used. The spectral density is the mean of the periodograms, scaled so that area under the spectrum is the same as the mean square of the data. This equivalence is supposed to be exact, but in practice there is a mismatch of up to 0.5% when comparing area under a periodogram with the mean square of the data. [spectra,freq] = pwelch(x,y,window,overlap,Nfft,Fs, range,plot_type,detrend,sloppy,results) Two-channel spectrum analyser. Estimate power spectral density, cross- spectral density, transfer function and/or coherence functions of time- series input data "x" and output data "y" by the Welch (1967) periodogram/FFT method. pwelch treats the second argument as "y" if there is a control-string argument "cross", "trans", "coher" or "ypower"; "power" does not force the 2nd argument to be treated as "y". All other arguments are optional. All spectra are returned in matrix "spectra". [spectra,Pxx_ci,freq] = pwelch(x,window,overlap,Nfft,Fs,conf, range,plot_type,detrend,sloppy) [spectra,Pxx_ci,freq] = pwelch(x,y,window,overlap,Nfft,Fs,conf, range,plot_type,detrend,sloppy,results) Estimates confidence intervals for the spectral density. See Hint (7) below for compatibility options. Confidence level "conf" is the 6th or 7th numeric argument. If "results" control-string arguments are used, one of them must be "power" when the "conf" argument is present; pwelch can estimate confidence intervals only for the power spectrum of the "x" data. It does not know how to estimate confidence intervals of the cross-power spectrum, transfer function or coherence; if you can suggest a good method, please send a bug report. ARGUMENTS All but the first argument are optional and may be empty, except that the "results" argument may require the second argument to be "y". @table @asis @item x [non-empty vector] system-input time-series data @item y [non-empty vector] system-output time-series data @item window [real vector] of window-function values between 0 and 1; the data segment has the same length as the window. Default window shape is Hamming. [integer scalar] length of each data segment. The default value is window=sqrt(length(x)) rounded up to the nearest integer power of 2; see 'sloppy' argument. @item overlap [real scalar] segment overlap expressed as a multiple of window or segment length. 0 <= overlap < 1, The default is overlap=0.5 . @item Nfft [integer scalar] Length of FFT. The default is the length of the "window" vector or has the same value as the scalar "window" argument. If Nfft is larger than the segment length, "seg_len", the data segment is padded with "Nfft-seg_len" zeros. The default is no padding. Nfft values smaller than the length of the data segment (or window) are ignored silently. @item Fs [real scalar] sampling frequency (Hertz); default=1.0 @item conf [real scalar] confidence level between 0 and 1. Confidence intervals of the spectral density are estimated from scatter in the periodograms and are returned as Pxx_ci. Pxx_ci(:,1) is the lower bound of the confidence interval and Pxx_ci(:,2) is the upper bound. If there are three return values, or conf is an empty matrix, confidence intervals are calculated for conf=0.95 . If conf is zero or is not given, confidence intervals are not calculated. Confidence intervals can be obtained only for the power spectral density of x; nothing else. @end table CONTROL-STRING ARGUMENTS -- each of these arguments is a character string. Control-string arguments must be after the other arguments but can be in any order. @table @asis @item range 'half', 'onesided' : frequency range of the spectrum is zero up to but not including Fs/2. Power from negative frequencies is added to the positive side of the spectrum, but not at zero or Nyquist (Fs/2) frequencies. This keeps power equal in time and spectral domains. See reference [2]. 'whole', 'twosided' : frequency range of the spectrum is -Fs/2 to Fs/2, with negative frequencies stored in "wrap around" order after the positive frequencies; e.g. frequencies for a 10-point 'twosided' spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 'shift', 'centerdc' : same as 'whole' but with the first half of the spectrum swapped with second half to put the zero-frequency value in the middle. (See "help fftshift". If data (x and y) are real, the default range is 'half', otherwise default range is 'whole'. @item plot_type 'plot', 'semilogx', 'semilogy', 'loglog', 'squared' or 'db': specifies the type of plot. The default is 'plot', which means linear-linear axes. 'squared' is the same as 'plot'. 'dB' plots "10*log10(psd)". This argument is ignored and a spectrum is not plotted if the caller requires a returned value. @item detrend 'no-strip', 'none' -- do NOT remove mean value from the data 'short', 'mean' -- remove the mean value of each segment from each segment of the data. 'linear', -- remove linear trend from each segment of the data. 'long-mean' -- remove the mean value from the data before splitting it into segments. This is the default. @item sloppy 'sloppy': FFT length is rounded up to the nearest integer power of 2 by zero padding. FFT length is adjusted after addition of padding by explicit Nfft argument. The default is to use exactly the FFT and window/ segment lengths specified in argument list. @item results specifies what results to return (in the order specified and as many as desired). 'power' calculate power spectral density of "x" 'cross' calculate cross spectral density of "x" and "y" 'trans' calculate transfer function of a system with input "x" and output "y" 'coher' calculate coherence function of "x" and "y" 'ypower' calculate power spectral density of "y" The default is 'power', with argument "y" omitted. @end table RETURNED VALUES: If return values are not required by the caller, the results are plotted and nothing is returned. @table @asis @item spectra [real-or-complex matrix] columns of the matrix contain results in the same order as specified by "results" arguments. Each column contains one of the result vectors. @item Pxx_ci [real matrix] estimate of confidence interval for power spectral density of x. First column is the lower bound. Second column is the upper bound. @item freq [real column vector] frequency values @end table HINTS @enumerate @item EMPTY ARGS: if you don't want to use an optional argument you can leave it empty by writing its value as []. @item FOR BEGINNERS: The profusion of arguments may make pwelch difficult to use, and an unskilled user can easily produce a meaningless result or can easily mis-interpret the result. With real data "x" and sampling frequency "Fs", the easiest and best way for a beginner to use pwelch is probably "pwelch(x,[],[],[],Fs)". Use the "window" argument to control the length of the spectrum vector. For real data and integer scalar M, "pwelch(x,2*M,[],[],Fs)" gives an M+1 point spectrum. Run "demo pwelch" (octave only). @item WINDOWING FUNCTIONS: Without a window function, sharp spectral peaks can have strong sidelobes because the FFT of a data in a segment is in effect convolved with a rectangular window. A window function which tapers off (gradually) at the ends produces much weaker sidelobes in the FFT. Hann (hanning), hamming, bartlett, blackman, flattopwin etc are available as separate Matlab/sigproc or Octave functions. The sidelobes of the Hann window have a roll-off rate of 60dB/decade of frequency. The first sidelobe of the Hamming window is suppressed and is about 12dB lower than the first Hann sidelobe, but the roll-off rate is only 20dB/decade. You can inspect the FFT of a Hann window by plotting "abs(fft(postpad(hanning(256),4096,0)))". The default window is Hamming. @item ZERO PADDING: Zero-padding reduces the frequency step in the spectrum, and produces an artificially smoothed spectrum. For example, "Nfft=2*length(window)" gives twice as many frequency values, but adjacent PSD (power spectral density) values are not independent; adjacent PSD values are independent if "Nfft=length(window)", which is the default value of Nfft. @item REMOVING MEAN FROM SIGNAL: If the mean is not removed from the signal there is a large spectral peak at zero frequency and the sidelobes of this peak are likely to swamp the rest of the spectrum. For this reason, the default behavior is to remove the mean. However, the matlab pwelch does not do this. @item WARNING ON CONFIDENCE INTERVALS Confidence intervals are obtained by measuring the sample variance of the periodograms and assuming that the periodograms have a Gaussian probability distribution. This assumption is not accurate. If, for example, the data (x) is Gaussian, the periodogram has a Rayleigh distribution. However, the confidence intervals may still be useful. @item COMPATIBILITY WITH Matlab R11, R12, etc When used without the second data (y) argument, arguments are compatible with the pwelch of Matlab R12, R13, R14, 2006a and 2006b except that 1) overlap is expressed as a multiple of window length --- effect of overlap scales with window length 2) default values of length(window), Nfft and Fs are more sensible, and 3) Goertzel algorithm is not available so Nfft cannot be an array of frequencies as in Matlab 2006b. Pwelch has four persistent Matlab-compatibility levels. Calling pwelch with an empty first argument sets the order of arguments and defaults specified above in the USAGE and ARGUMENTS section of this documentation. @example prev_compat=pwelch([]); [Pxx,f]=pwelch(x,window,overlap,Nfft,Fs,conf,...); @end example Calling pwelch with a single string argument (as described below) gives compatibility with Matlab R11 or R12, or the R14 spectrum.welch defaults. The returned value is the PREVIOUS compatibility string. Matlab R11: For compatibility with the Matlab R11 pwelch: @example prev_compat=pwelch('R11-'); [Pxx,f]=pwelch(x,Nfft,Fs,window,overlap,conf,range,units); %% units of overlap are "number of samples" %% defaults: Nfft=min(length(x),256), Fs=2*pi, length(window)=Nfft, %% window=Hanning, do not detrend, %% N.B. "Sloppy" is not available. @end example Matlab R12: For compatibility with Matlab R12 to 2006a pwelch: @example prev_compat=pwelch('R12+'); [Pxx,f]=pwelch(x,window,overlap,nfft,Fs,...); %% units of overlap are "number of samples" %% defaults: length(window)==length(x)/8, window=Hamming, %% Nfft=max(256,NextPow2), Fs=2*pi, do not detrend %% NextPow2 is the next power of 2 greater than or equal to the %% window length. "Sloppy", "conf" are not available. Default %% window length gives very poor amplitude resolution. @end example To adopt defaults of the Matlab R14 "spectrum.welch" spectrum object associated "psd" method. @example prev_compat=pwelch('psd'); [Pxx,f] = pwelch(x,window,overlap,Nfft,Fs,conf,...); %% overlap is expressed as a percentage of window length, %% defaults: length(window)==64, Nfft=max(256,NextPow2), Fs=2*pi %% do not detrend %% NextPow2 is the next power of 2 greater than or equal to the %% window length. "Sloppy" is not available. %% Default window length gives coarse frequency resolution. @end example @end enumerate REFERENCES [1] Peter D. Welch (June 1967): "The use of fast Fourier transform for the estimation of power spectra: a method based on time averaging over short, modified periodograms." IEEE Transactions on Audio Electroacoustics, Vol AU-15(6), pp 70-73 [2] William H. Press and Saul A. Teukolsky and William T. Vetterling and Brian P. Flannery", "Numerical recipes in C, The art of scientific computing", 2nd edition, Cambridge University Press, 2002 --- Section 13.7. @end deftypefn @c Power Spectrum Analysis pyulear @c ----------------------------------------- @subsection pyulear @cindex pyulear @deftypefn {Function File} {[psd,f_out] =} pyulear(x,poles,freq,Fs,range,method,plot_type) Calculates a Yule-Walker autoregressive (all-pole) model of the data "x" and computes the power spectrum of the model. This is a wrapper for functions "aryule" and "ar_psd" which perform the argument checking. See "help aryule" and "help ar_psd" for further details. ARGUMENTS: All but the first two arguments are optional and may be empty. @table @asis @item x [vector] sampled data @item poles [integer scalar] required number of poles of the AR model @item freq [real vector] frequencies at which power spectral density is calculated [integer scalar] number of uniformly distributed frequency values at which spectral density is calculated. [default=256] @item Fs [real scalar] sampling frequency (Hertz) [default=1] @end table CONTROL-STRING ARGUMENTS -- each of these arguments is a character string. Control-string arguments can be in any order after the other arguments. @table @asis @item range 'half', 'onesided' : frequency range of the spectrum is from zero up to but not including sample_f/2. Power from negative frequencies is added to the positive side of the spectrum. 'whole', 'twosided' : frequency range of the spectrum is -sample_f/2 to sample_f/2, with negative frequencies stored in "wrap around" order after the positive frequencies; e.g. frequencies for a 10-point 'twosided' spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 'shift', 'centerdc' : same as 'whole' but with the first half of the spectrum swapped with second half to put the zero-frequency value in the middle. (See "help fftshift". If "freq" is vector, 'shift' is ignored. If model coefficients "ar_coeffs" are real, the default range is 'half', otherwise default range is 'whole'. @item method 'fft': use FFT to calculate power spectrum. 'poly': calculate power spectrum as a polynomial of 1/z N.B. this argument is ignored if the "freq" argument is a vector. The default is 'poly' unless the "freq" argument is an integer power of 2. @item plot_type 'plot', 'semilogx', 'semilogy', 'loglog', 'squared' or 'db': specifies the type of plot. The default is 'plot', which means linear-linear axes. 'squared' is the same as 'plot'. 'dB' plots "10*log10(psd)". This argument is ignored and a spectrum is not plotted if the caller requires a returned value. @end table RETURNED VALUES: If return values are not required by the caller, the spectrum is plotted and nothing is returned. @table @asis @item psd [real vector] power-spectrum estimate @item f_out [real vector] frequency values @end table HINTS This function is a wrapper for aryule and ar_psd. See "help aryule", "help ar_psd". @end deftypefn @c Power Spectrum Analysis tfe @c ----------------------------------------- @subsection tfe @cindex tfe @deftypefn {Function File} {[Pxx,freq] =} tfe(x,y,Nfft,Fs,window,overlap,range,plot_type,detrend) Estimate transfer function of system with input "x" and output "y". Use the Welch (1967) periodogram/FFT method. Compatible with Matlab R11 tfe and earlier. See "help pwelch" for description of arguments, hints and references --- especially hint (7) for Matlab R11 defaults. @end deftypefn @c Power Spectrum Analysis tfestimate @c ----------------------------------------- @subsection tfestimate @cindex tfestimate @deftypefn {Function File} {} tfestimate (@var{x}, @var{y}) @deftypefnx {Function File} {} tfestimate (@var{x}, @var{y}, @var{window}) @deftypefnx {Function File} {} tfestimate (@var{x}, @var{y}, @var{window}, @var{overlap}) @deftypefnx {Function File} {} tfestimate (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}) @deftypefnx {Function File} {} tfestimate (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}) @deftypefnx {Function File} {} tfestimate (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}, @var{range}) @deftypefnx {Function File} {[@var{Pxx}, @var{freq}] =} tfestimate (@dots{}) Estimate transfer function of system with input @var{x} and output @var{y}. Use the Welch (1967) periodogram/FFT method. @xseealso{pwelch} @end deftypefn @c --------------------------------------------------- @node Window Functions @section Window Functions @cindex Window Functions @c Window Functions barthannwin @c ----------------------------------------- @subsection barthannwin @cindex barthannwin @deftypefn {Function File} {} barthannwin (@var{m}) Return the filter coefficients of a modified Bartlett-Hann window of length @var{m}. @xseealso{rectwin, bartlett} @end deftypefn @c Window Functions blackmanharris @c ----------------------------------------- @subsection blackmanharris @cindex blackmanharris @deftypefn {Function File} {} blackmanharris (@var{m}) @deftypefnx {Function File} {} blackmanharris (@var{m}, "periodic") @deftypefnx {Function File} {} blackmanharris (@var{m}, "symmetric") Return the filter coefficients of a Blackman-Harris window of length @var{m}. If the optional argument @code{"periodic"} is given, the periodic form of the window is returned. This is equivalent to the window of length @var{m}+1 with the last coefficient removed. The optional argument @code{"symmetric"} is equivalent to not specifying a second argument. @xseealso{rectwin, bartlett} @end deftypefn @c Window Functions blackmannuttall @c ----------------------------------------- @subsection blackmannuttall @cindex blackmannuttall @deftypefn {Function File} {} blackmannuttall (@var{m}) @deftypefnx {Function File} {} blackmannuttall (@var{m}, "periodic") @deftypefnx {Function File} {} blackmannuttall (@var{m}, "symmetric") Return the filter coefficients of a Blackman-Nuttall window of length @var{m}. If the optional argument @code{"periodic"} is given, the periodic form of the window is returned. This is equivalent to the window of length @var{m}+1 with the last coefficient removed. The optional argument @code{"symmetric"} is equivalent to not specifying a second argument. @xseealso{nuttallwin, kaiser} @end deftypefn @c Window Functions bohmanwin @c ----------------------------------------- @subsection bohmanwin @cindex bohmanwin @deftypefn {Function File} {} bohmanwin (@var{m}) Return the filter coefficients of a Bohman window of length @var{m}. @xseealso{rectwin, bartlett} @end deftypefn @c Window Functions boxcar @c ----------------------------------------- @subsection boxcar @cindex boxcar @deftypefn {Function File} {} boxcar (@var{m}) Return the filter coefficients of a rectangular window of length @var{m}. @end deftypefn @c Window Functions chebwin @c ----------------------------------------- @subsection chebwin @cindex chebwin @deftypefn {Function File} {} chebwin (@var{m}) @deftypefnx {Function File} {} chebwin (@var{m}, @var{at}) Return the filter coefficients of a Dolph-Chebyshev window of length @var{m}. The Fourier transform of the window has a stop-band attenuation of @var{at} dB. The default attenuation value is 100 dB. For the definition of the Chebyshev window, see * Peter Lynch, "The Dolph-Chebyshev Window: A Simple Optimal Filter", Monthly Weather Review, Vol. 125, pp. 655-660, April 1997. (http://www.maths.tcd.ie/~plynch/Publications/Dolph.pdf) * C. Dolph, "A current distribution for broadside arrays which optimizes the relationship between beam width and side-lobe level", Proc. IEEE, 34, pp. 335-348. The window is described in frequency domain by the expression: @example @group Cheb(m-1, beta * cos(pi * k/m)) W(k) = ------------------------------- Cheb(m-1, beta) @end group @end example with @example @group beta = cosh(1/(m-1) * acosh(10^(at/20)) @end group @end example and Cheb(m,x) denoting the m-th order Chebyshev polynomial calculated at the point x. Note that the denominator in W(k) above is not computed, and after the inverse Fourier transform the window is scaled by making its maximum value unitary. @xseealso{kaiser} @end deftypefn @c Window Functions flattopwin @c ----------------------------------------- @subsection flattopwin @cindex flattopwin @deftypefn {Function File} {} flattopwin (@var{m}) @deftypefnx {Function File} {} flattopwin (@var{m}, "periodic") @deftypefnx {Function File} {} flattopwin (@var{m}, "symmetric") Return the filter coefficients of a Flat Top window of length @var{m}. The Flat Top window is defined by the function f(w): @example @group f(w) = 1 - 1.93 cos(2 pi w) + 1.29 cos(4 pi w) - 0.388 cos(6 pi w) + 0.0322cos(8 pi w) @end group @end example where w = i/(m-1) for i=0:m-1 for a symmetric window, or w = i/m for i=0:m-1 for a periodic window. The default is symmetric. The returned window is normalized to a peak of 1 at w = 0.5. This window has low pass-band ripple, but high bandwidth. According to [1]: The main use for the Flat Top window is for calibration, due to its negligible amplitude errors. [1] Gade, S; Herlufsen, H; (1987) "Use of weighting functions in DFT/FFT analysis (Part I)", Bruel & Kjaer Technical Review No.3. @end deftypefn @c Window Functions gaussian @c ----------------------------------------- @subsection gaussian @cindex gaussian @deftypefn {Function File} {} gaussian (@var{m}) @deftypefnx {Function File} {} gaussian (@var{m}, @var{a}) Return a Gaussian convolution window of length @var{m}. The width of the window is inversely proportional to the parameter @var{a}. Use larger @var{a} for a narrower window. Use larger @var{m} for longer tails. w = exp ( -(a*x)^2/2 ) for x = linspace ( -(m-1)/2, (m-1)/2, m ). Width a is measured in frequency units (sample rate/num samples). It should be f when multiplying in the time domain, but 1/f when multiplying in the frequency domain (for use in convolutions). @end deftypefn @c Window Functions gausswin @c ----------------------------------------- @subsection gausswin @cindex gausswin @deftypefn {Function File} {} gausswin (@var{m}) @deftypefnx {Function File} {} gausswin (@var{m}, @var{a}) Return the filter coefficients of a Gaussian window of length @var{m}. The width of the window is inversely proportional to the parameter @var{a}. Use larger @var{a} for a narrow window. Use larger @var{m} for a smoother curve. w = exp ( -(a*x)^2/2 ) for x = linspace(-(m-1)/m, (m-1)/m, m) @end deftypefn @c Window Functions hann @c ----------------------------------------- @subsection hann @cindex hann @deftypefn {Function File} {} hann (@var{m}) @deftypefnx {Function File} {} hann (@var{m}, "periodic") @deftypefnx {Function File} {} hann (@var{m}, "symmetric") Return the filter coefficients of a Hanning window of length @var{m}. If the optional argument @code{"periodic"} is given, the periodic form of the window is returned. This is equivalent to the window of length @var{m}+1 with the last coefficient removed. The optional argument @code{"symmetric"} is equivalent to not specifying a second argument. This function exists for @sc{matlab} compatibility only, and is equivalent to @code{hanning (@var{m})}. @xseealso{hanning} @end deftypefn @c Window Functions kaiser @c ----------------------------------------- @subsection kaiser @cindex kaiser @deftypefn {Function File} {} kaiser (@var{m}) @deftypefnx {Function File} {} kaiser (@var{m}, @var{beta}) Return the filter coefficients of a Kaiser window of length @var{m}. The Fourier transform of the window has a stop-band attenuation that is derived from the parameter @var{beta}. For the definition of the Kaiser window, see A. V. Oppenheim & R. W. Schafer, "Discrete-Time Signal Processing". The continuous version of width m centered about x=0 is: @example @group besseli(0, beta * sqrt(1-(2*x/m).^2)) k(x) = -------------------------------------, m/2 <= x <= m/2 besseli(0, beta) @end group @end example @xseealso{kaiserord} @end deftypefn @c Window Functions nuttallwin @c ----------------------------------------- @subsection nuttallwin @cindex nuttallwin @deftypefn {Function File} {} nuttallwin (@var{m}) @deftypefnx {Function File} {} nuttallwin (@var{m}, "periodic") @deftypefnx {Function File} {} nuttallwin (@var{m}, "symmetric") Return the filter coefficients of a Blackman-Harris window defined by Nuttall of length @var{m}. If the optional argument @code{"periodic"} is given, the periodic form of the window is returned. This is equivalent to the window of length @var{m}+1 with the last coefficient removed. The optional argument @code{"symmetric"} is equivalent to not specifying a second argument. @xseealso{blackman, blackmanharris} @end deftypefn @c Window Functions parzenwin @c ----------------------------------------- @subsection parzenwin @cindex parzenwin @deftypefn {Function File} {} parzenwin (@var{m}) Return the filter coefficients of a Parzen window of length @var{m}. @xseealso{rectwin, bartlett} @end deftypefn @c Window Functions rectwin @c ----------------------------------------- @subsection rectwin @cindex rectwin @deftypefn {Function File} {} rectwin (@var{m}) Return the filter coefficients of a rectangular window of length @var{m}. @xseealso{boxcar, hamming, hanning} @end deftypefn @c Window Functions triang @c ----------------------------------------- @subsection triang @cindex triang @deftypefn {Function File} {} triang (@var{m}) Return the filter coefficients of a triangular window of length @var{m}. Unlike the Bartlett window, @code{triang} does not go to zero at the edges of the window. For odd @var{m}, @code{triang (@var{m})} is equal to @code{bartlett (@var{m} + 2)} except for the zeros at the edges of the window. @xseealso{bartlett} @end deftypefn @c Window Functions tukeywin @c ----------------------------------------- @subsection tukeywin @cindex tukeywin @deftypefn {Function File} {} tukeywin (@var{m}) @deftypefnx {Function File} {} tukeywin (@var{m}, @var{r}) Return the filter coefficients of a Tukey window (also known as the cosine-tapered window) of length @var{m}. @var{r} defines the ratio between the constant section and and the cosine section. It has to be between 0 and 1. The function returns a Hanning window for @var{r} equal to 1 and a rectangular window for @var{r} equal to 0. The default value of @var{r} is 1/2. For a definition of the Tukey window, see e.g. Fredric J. Harris, "On the Use of Windows for Harmonic Analysis with the Discrete Fourier Transform, Proceedings of the IEEE", Vol. 66, No. 1, January 1978, Page 67, Equation 38. @xseealso{hanning} @end deftypefn @c Window Functions ultrwin @c ----------------------------------------- @subsection ultrwin @cindex ultrwin @deftypefn {Function File} {[@var{w}, @var{xmu}] =} ultrwin (@var{m}, @var{mu}, @var{beta}) @deftypefnx {Function File} {[@var{w}, @var{xmu}] =} ultrwin (@var{m}, @var{mu}, @var{att}, "att") @deftypefnx {Function File} {[@var{w}, @var{xmu}] =} ultrwin (@var{m}, @var{mu}, @var{latt}, "latt") @deftypefnx {Function File} {@var{w} =} ultrwin (@var{m}, @var{mu}, @var{xmu}, "xmu") Return the coefficients of an Ultraspherical window of length @var{m}. The parameter @var{mu} controls the window's Fourier transform's side-lobe to side-lobe ratio, and the third given parameter controls the transform's main-lobe width/side-lobe-ratio; normalize @var{w} such that the central coefficient(s) value is unitary. By default, the third parameter is @var{beta}, which sets the main lobe width to @var{beta} times that of a rectangular window. Alternatively, giving @var{att} or @var{latt} sets the ripple ratio at the first or last side-lobe respectively, or giving @var{xmu} sets the (un-normalized) window's Fourier transform according to its canonical definition: @verbatim (MU) W(k) = C [ XMU cos(pi k/M) ], k = 0, 1, ..., M-1, M-1 @end verbatim where C is the Ultraspherical (a.k.a. Gegenbauer) polynomial, which can be defined using the recurrence relationship: @verbatim (l) 1 (l) (l) C (x) = - [ 2x(m + l - 1) C (x) - (m + 2l - 2) C (x) ] m m m-1 m-2 (l) (l) for m an integer > 1, and C (x) = 1, C (x) = 2lx. 0 1 @end verbatim For given @var{beta}, @var{att}, or @var{latt}, the corresponding (determined) value of @var{xmu} is also returned. The Dolph-Chebyshev and Saramaki windows are special cases of the Ultraspherical window, with @var{mu} set to 0 and 1 respectively. Note that when not giving @var{xmu}, stability issues may occur with @var{mu} <= -1.5. For further information about the window, see @itemize @bullet @item Kabal, P., 2009: Time Windows for Linear Prediction of Speech. Technical Report, Dept. Elec. & Comp. Eng., McGill University. @item Bergen, S., Antoniou, A., 2004: Design of Ultraspherical Window Functions with Prescribed Spectral Characteristics. Proc. JASP, 13/13, pp. 2053-2065. @item Streit, R., 1984: A two-parameter family of weights for nonrecursive digital filters and antennas. Trans. ASSP, 32, pp. 108-118. @end itemize @xseealso{chebwin, kaiser} @end deftypefn @c Window Functions welchwin @c ----------------------------------------- @subsection welchwin @cindex welchwin @deftypefn {Function File} {} welchwin (@var{m}) @deftypefnx {Function File} {} welchwin (@var{m}, "periodic") @deftypefnx {Function File} {} welchwin (@var{m}, "symmetric") Return the filter coefficients of a Welch window of length @var{m}. The Welch window is given by @var{w}(n)=1-(n/N-1)^2, n=[0,1, ... @var{m}-1]. The optional argument specifies a "symmetric" window (the default) or a "periodic" window. A symmetric window has zero at each end and maximum in the middle, and the length must be an integer greater than 2. The variable @var{N} in the formula above is @code{(@var{m}-1)/2}. A periodic window wraps around the cyclic interval [0,1, ... @var{m}-1], and is intended for use with the DFT. The length must be an integer greater than 1. The variable @var{N} in the formula above is @code{@var{m}/2}. @xseealso{blackman, kaiser} @end deftypefn @c Window Functions window @c ----------------------------------------- @subsection window @cindex window @deftypefn {Function File} {@var{w} =} window (@var{f}, @var{m}) @deftypefnx {Function File} {@var{w} =} window (@var{f}, @var{m}, @var{opts}) Create an @var{m}-point window from the function @var{f}. The function @var{f} can be for example @code{@@blackman}. Any additional arguments @var{opt} are passed to the windowing function. @end deftypefn @c --------------------------------------------------- @node System Identification @section System Identification @cindex System Identification @c System Identification arburg @c ----------------------------------------- @subsection arburg @cindex arburg @deftypefn {Function File} {[@var{a}, @var{v}, @var{k}] =} arburg (@var{x}, @var{poles}) @deftypefnx {Function File} {[@var{a}, @var{v}, @var{k}] =} arburg (@var{x}, @var{poles}, @var{criterion}) Calculate coefficients of an autoregressive (AR) model of complex data @var{x} using the whitening lattice-filter method of Burg (1968). The inverse of the model is a moving-average filter which reduces @var{x} to white noise. The power spectrum of the AR model is an estimate of the maximum entropy power spectrum of the data. The function @code{ar_psd} calculates the power spectrum of the AR model. ARGUMENTS: @itemize @item @var{x} sampled data @item @var{poles} number of poles in the AR model or limit to the number of poles if a valid @var{criterion} is provided. @item @var{criterion} model-selection criterion. Limits the number of poles so that spurious poles are not added when the whitened data has no more information in it (see Kay & Marple, 1981). Recognized values are 'AKICc' -- approximate corrected Kullback information criterion (recommended), 'KIC' -- Kullback information criterion 'AICc' -- corrected Akaike information criterion 'AIC' -- Akaike information criterion 'FPE' -- final prediction error" criterion The default is to NOT use a model-selection criterion @end itemize RETURNED VALUES: @itemize @item @var{a} list of (P+1) autoregression coefficients; for data input @math{x(n)} and white noise @math{e(n)}, the model is @example @group P+1 x(n) = sqrt(v).e(n) + SUM a(k).x(n-k) k=1 @end group @end example @var{v} mean square of residual noise from the whitening operation of the Burg lattice filter. @item @var{k} reflection coefficients defining the lattice-filter embodiment of the model @end itemize HINTS: (1) arburg does not remove the mean from the data. You should remove the mean from the data if you want a power spectrum. A non-zero mean can produce large errors in a power-spectrum estimate. See "help detrend". (2) If you don't know what the value of "poles" should be, choose the largest (reasonable) value you could want and use the recommended value, criterion='AKICc', so that arburg can find it. E.g. arburg(x,64,'AKICc') The AKICc has the least bias and best resolution of the available model-selection criteria. (3) Autoregressive and moving-average filters are stored as polynomials which, in matlab, are row vectors. NOTE ON SELECTION CRITERION: AIC, AICc, KIC and AKICc are based on information theory. They attempt to balance the complexity (or length) of the model against how well the model fits the data. AIC and KIC are biased estimates of the asymmetric and the symmetric Kullback-Leibler divergence respectively. AICc and AKICc attempt to correct the bias. See reference [4]. REFERENCES: [1] John Parker Burg (1968) "A new analysis technique for time series data", NATO advanced study Institute on Signal Processing with Emphasis on Underwater Acoustics, Enschede, Netherlands, Aug. 12-23, 1968. [2] Steven M. Kay and Stanley Lawrence Marple Jr.: "Spectrum analysis -- a modern perspective", Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981 [3] William H. Press and Saul A. Teukolsky and William T. Vetterling and Brian P. Flannery "Numerical recipes in C, The art of scientific computing", 2nd edition, Cambridge University Press, 2002 --- Section 13.7. [4] Abd-Krim Seghouane and Maiza Bekara "A small sample model selection criterion based on Kullback's symmetric divergence", IEEE Transactions on Signal Processing, Vol. 52(12), pp 3314-3323, Dec. 2004 @xseealso{ar_psd} @end deftypefn @c System Identification aryule @c ----------------------------------------- @subsection aryule @cindex aryule @deftypefn {Function File} {@var{a} =} aryule (@var{x}, @var{p}) @deftypefnx {Function File} {[@var{a}, @var{v}, @var{k}] =} aryule (@var{x}, @var{p}) Fit an AR (@var{p})-model with Yule-Walker estimates. @table @var @item x data vector to estimate @item a AR coefficients @item v variance of white noise @item k reflection coefficients for use in lattice filter @end table The power spectrum of the resulting filter can be plotted with pyulear(x, p), or you can plot it directly with ar_psd(a,v,...). See also: pyulear, power, freqz, impz -- for observing characteristics of the model arburg -- for alternative spectral estimators Example: Use example from arburg, but substitute aryule for arburg. Note: Orphanidis '85 claims lattice filters are more tolerant of truncation errors, which is why you might want to use them. However, lacking a lattice filter processor, I haven't tested that the lattice filter coefficients are reasonable. @end deftypefn @c System Identification invfreq @c ----------------------------------------- @subsection invfreq @cindex invfreq @deftypefn {Function File} {[B,A] =} invfreq(H,F,nB,nA) @deftypefnx {} {[B,A] =} invfreq(H,F,nB,nA,W) @deftypefnx {} {[B,A] =} invfreq(H,F,nB,nA,W,[],[],plane) @deftypefnx {} {[B,A] =} invfreq(H,F,nB,nA,W,iter,tol,plane) Fit filter B(z)/A(z) or B(s)/A(s) to complex frequency response at frequency points F. A and B are real polynomial coefficients of order nA and nB respectively. Optionally, the fit-errors can be weighted vs frequency according to the weights W. Also, the transform plane can be specified as either 's' for continuous time or 'z' for discrete time. 'z' is chosen by default. Eventually, Steiglitz-McBride iterations will be specified by iter and tol. H: desired complex frequency response It is assumed that A and B are real polynomials, hence H is one-sided. F: vector of frequency samples in radians nA: order of denominator polynomial A nB: order of numerator polynomial B plane='z': F on unit circle (discrete-time spectra, z-plane design) plane='s': F on jw axis (continuous-time spectra, s-plane design) H(k) = spectral samples of filter frequency response at points zk, where zk=exp(sqrt(-1)*F(k)) when plane='z' (F(k) in [0,.5]) and zk=(sqrt(-1)*F(k)) when plane='s' (F(k) nonnegative) Example: @example [B,A] = butter(12,1/4); [H,w] = freqz(B,A,128); [Bh,Ah] = invfreq(H,F,4,4); Hh = freqz(Bh,Ah); disp(sprintf('||frequency response error|| = %f',norm(H-Hh))); @end example References: J. O. Smith, "Techniques for Digital Filter Design and System Identification with Application to the Violin, Ph.D. Dissertation, Elec. Eng. Dept., Stanford University, June 1983, page 50; or, http://ccrma.stanford.edu/~jos/filters/FFT_Based_Equation_Error_Method.html @end deftypefn @c System Identification invfreqs @c ----------------------------------------- @subsection invfreqs @cindex invfreqs @deftypefn {Function File} {[B,A] =} invfreqs(H,F,nB,nA) @deftypefnx {} {[B,A] =} invfreqs(H,F,nB,nA,W) @deftypefnx {} {[B,A] =} invfreqs(H,F,nB,nA,W,iter,tol,'trace') Fit filter B(s)/A(s)to the complex frequency response H at frequency points F. A and B are real polynomial coefficients of order nA and nB. Optionally, the fit-errors can be weighted vs frequency according to the weights W. Note: all the guts are in invfreq.m H: desired complex frequency response F: frequency (must be same length as H) nA: order of the denominator polynomial A nB: order of the numerator polynomial B W: vector of weights (must be same length as F) Example: @example B = [1/2 1]; A = [1 1]; w = linspace(0,4,128); H = freqs(B,A,w); [Bh,Ah] = invfreqs(H,w,1,1); Hh = freqs(Bh,Ah,w); plot(w,[abs(H);abs(Hh)]) legend('Original','Measured'); err = norm(H-Hh); disp(sprintf('L2 norm of frequency response error = %f',err)); @end example @end deftypefn @c System Identification invfreqz @c ----------------------------------------- @subsection invfreqz @cindex invfreqz @deftypefn {Function File} {[B,A] =} invfreqz(H,F,nB,nA) @deftypefnx {} {[B,A] =} invfreqz(H,F,nB,nA,W) @deftypefnx {} {[B,A] =} invfreqz(H,F,nB,nA,W,iter,tol,'trace') Fit filter B(z)/A(z)to the complex frequency response H at frequency points F. A and B are real polynomial coefficients of order nA and nB. Optionally, the fit-errors can be weighted vs frequency according to the weights W. Note: all the guts are in invfreq.m H: desired complex frequency response F: normalized frequency (0 to pi) (must be same length as H) nA: order of the denominator polynomial A nB: order of the numerator polynomial B W: vector of weights (must be same length as F) Example: @example [B,A] = butter(4,1/4); [H,F] = freqz(B,A); [Bh,Ah] = invfreq(H,F,4,4); Hh = freqz(Bh,Ah); disp(sprintf('||frequency response error|| = %f',norm(H-Hh))); @end example @end deftypefn @c System Identification levinson @c ----------------------------------------- @subsection levinson @cindex levinson @deftypefn {Function File} {[@var{a}, @var{v}, @var{ref}] =} levinson (@var{acf}) @deftypefnx {Function File} {[@dots{}] =} levinson (@var{acf}, @var{p}) Use the Durbin-Levinson algorithm to solve: toeplitz(acf(1:p)) * x = -acf(2:p+1). The solution [1, x'] is the denominator of an all pole filter approximation to the signal x which generated the autocorrelation function acf. acf is the autocorrelation function for lags 0 to p. p defaults to length(acf)-1. Returns a=[1, x'] the denominator filter coefficients. v= variance of the white noise = square of the numerator constant ref = reflection coefficients = coefficients of the lattice implementation of the filter Use freqz(sqrt(v),a) to plot the power spectrum. REFERENCE [1] Steven M. Kay and Stanley Lawrence Marple Jr.: "Spectrum analysis -- a modern perspective", Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981 @end deftypefn @c System Identification lpc @c ----------------------------------------- @subsection lpc @cindex lpc @deftypefn {Function File} {@var{a} = } lpc (@var{x}) @deftypefnx {Function File} {@var{a} = } lpc (@var{x}, @var{p}) @deftypefnx {Function File} {[@var{a}, @var{g}] = } lpc (@dots{}) @deftypefnx {Function File} {[@var{a}, @var{g}] = } lpc (@var{x}, @var{p}) Determines the forward linear predictor by minimizing the prediction error in the least squares sense. Use the Durbin-Levinson algorithm to solve the Yule-Walker equations obtained by the autocorrelation of the input signal. @var{x} is a data vector used to estimate the lpc model of @var{p}-th order, given by the prediction polynomial @code{@var{a} = [1 @var{a}(2) @dots{} @var{a}(@var{p}+1)]}. If @var{p} is not provided, @code{length(@var{p}) - 1} is used as default. @var{x} might also be a matrix, in which case each column is regarded as a separate signal. @code{lpc} will return a model estimate for each column of @var{x}. @var{g} is the variance (power) of the prediction error for each signal in @var{x}. @xseealso{aryule,levinson} @end deftypefn @c --------------------------------------------------- @node Sample Rate Change @section Sample Rate Change @cindex Sample Rate Change @c Sample Rate Change data2fun @c ----------------------------------------- @subsection data2fun @cindex data2fun @deftypefn {Function File} {[@var{fhandle}, @var{fullname}] =} data2fun (@var{ti}, @var{yi}) @deftypefnx {Function File} {[@dots{}] =} data2fun (@dots{}, @var{property}, @var{value}) Create a vectorized function based on data samples using interpolation. The values given in @var{yi} (N-by-k matrix) correspond to evaluations of the function y(t) at the points @var{ti} (N-by-1 matrix). The data is interpolated and the function handle to the generated interpolant is returned. The function accepts @var{property}-@var{value} pairs described below. @table @samp @item file Code is generated and .m file is created. The @var{value} contains the name of the function. The returned function handle is a handle to that file. If @var{value} is empty, then a name is automatically generated using @code{tempname} and the file is created in the current directory. @var{value} must not have an extension, since .m will be appended. Numerical values used in the function are stored in a .mat file with the same name as the function. @item interp Type of interpolation. See @code{interp1}. @end table @xseealso{interp1} @end deftypefn @c Sample Rate Change decimate @c ----------------------------------------- @subsection decimate @cindex decimate @deftypefn {Function File} {@var{y} =} decimate (@var{x}, @var{q}) @deftypefnx {Function File} {@var{y} =} decimate (@var{x}, @var{q}, @var{n}) @deftypefnx {Function File} {@var{y} =} decimate (@dots{}, "fir") Downsample the signal @var{x} by a reduction factor of @var{q}. A lowpass antialiasing filter is applied to the signal prior to reducing the input sequence. By default, an order @var{n} Chebyshev type I filter is used. If @var{n} is not specified, the default is 8. If the optional argument @code{"fir"} is given, an order @var{n} FIR filter is used, with a default order of 30 if @var{n} is not given. Note that @var{q} must be an integer for this rate change method. Example: @example ## Generate a signal that starts away from zero, is slowly varying ## at the start and quickly varying at the end, decimate and plot. ## Since it starts away from zero, you will see the boundary ## effects of the antialiasing filter clearly. Next you will see ## how it follows the curve nicely in the slowly varying early ## part of the signal, but averages the curve in the quickly ## varying late part of the signal. t = 0:0.01:2; x = chirp (t, 2, .5, 10, "quadratic") + sin (2*pi*t*0.4); y = decimate (x, 4); stem (t(1:121) * 1000, x(1:121), "-g;Original;"); hold on; # original stem (t(1:4:121) * 1000, y(1:31), "-r;Decimated;"); hold off; # decimated @end example @end deftypefn @c Sample Rate Change downsample @c ----------------------------------------- @subsection downsample @cindex downsample @deftypefn {Function File} {@var{y} =} downsample (@var{x}, @var{n}) @deftypefnx {Function File} {@var{y} =} downsample (@var{x}, @var{n}, @var{offset}) Downsample the signal, selecting every @var{n}th element. If @var{x} is a matrix, downsample every column. For most signals you will want to use @code{decimate} instead since it prefilters the high frequency components of the signal and avoids aliasing effects. If @var{offset} is defined, select every @var{n}th element starting at sample @var{offset}. @xseealso{decimate, interp, resample, upfirdn, upsample} @end deftypefn @c Sample Rate Change interp @c ----------------------------------------- @subsection interp @cindex interp @deftypefn {Function File} {@var{y} =} interp (@var{x}, @var{q}) @deftypefnx {Function File} {@var{y} =} interp (@var{x}, @var{q}, @var{n}) @deftypefnx {Function File} {@var{y} =} interp (@var{x}, @var{q}, @var{n}, @var{Wc}) Upsample the signal x by a factor of q, using an order 2*q*n+1 FIR filter. Note that q must be an integer for this rate change method. n defaults to 4 and Wc defaults to 0.5. Example @example @group # Generate a signal. t=0:0.01:2; x=chirp(t,2,.5,10,'quadratic')+sin(2*pi*t*0.4); y = interp(x(1:4:length(x)),4,4,1); # interpolate a sub-sample stem(t(1:121)*1000,x(1:121),"-g;Original;"); hold on; stem(t(1:121)*1000,y(1:121),"-r;Interpolated;"); stem(t(1:4:121)*1000,x(1:4:121),"-b;Subsampled;"); hold off; @end group @end example @xseealso{decimate, resample} @end deftypefn @c Sample Rate Change resample @c ----------------------------------------- @subsection resample @cindex resample @deftypefn {Function File} {[@var{y}, @var{h}] =} resample (@var{x}, @var{p}, @var{q}) @deftypefnx {Function File} {@var{y} =} resample (@var{x}, @var{p}, @var{q}, @var{h}) Change the sample rate of @var{x} by a factor of @var{p}/@var{q}. This is performed using a polyphase algorithm. The impulse response @var{h} of the antialiasing filter is either specified or either designed with a Kaiser-windowed sinecard. Ref [1] J. G. Proakis and D. G. Manolakis, Digital Signal Processing: Principles, Algorithms, and Applications, 4th ed., Prentice Hall, 2007. Chap. 6 Ref [2] A. V. Oppenheim, R. W. Schafer and J. R. Buck, Discrete-time signal processing, Signal processing series, Prentice-Hall, 1999 @end deftypefn @c Sample Rate Change upfirdn @c ----------------------------------------- @subsection upfirdn @cindex upfirdn @deftypefn {Loadable Function} {@var{y} =} upfirdn (@var{x}, @var{h}, @var{p}, @var{q}) Upsample, FIR filtering, and downsample. @end deftypefn @c Sample Rate Change upsample @c ----------------------------------------- @subsection upsample @cindex upsample @deftypefn {Function File} {@var{y} =} upsample (@var{x}, @var{n}) @deftypefnx {Function File} {@var{y} =} upsample (@var{x}, @var{n}, @var{offset}) Upsample the signal, inserting @var{n}-1 zeros between every element. If @var{x} is a matrix, upsample every column. If @var{offset} is specified, control the position of the inserted sample in the block of @var{n} zeros. @xseealso{decimate, downsample, interp, resample, upfirdn} @end deftypefn @c --------------------------------------------------- @node Pulse Metrics @section Pulse Metrics @cindex Pulse Metrics @c Pulse Metrics statelevels @c ----------------------------------------- @subsection statelevels @cindex statelevels @deftypefn {Function File} {@var{levels} =} statelevels (@var{A}) @deftypefnx {Function File} {@var{levels} =} statelevels (@var{A}, @var{nbins}) @deftypefnx {Function File} {@var{levels} =} statelevels (@var{A}, @var{nbins}, @var{method}) @deftypefnx {Function File} {@var{levels} =} statelevels (@var{A}, @var{nbins}, @var{method}, @var{bounds}) @deftypefnx {Function File} {[@var{levels}, @var{histograms}] =} statelevels (@dots{}) @deftypefnx {Function File} {[@var{levels}, @var{histograms}, @var{binlevels}] =} statelevels (@dots{}) @deftypefnx {Function File} {} statelevels (@dots{}) Estimate state-level for bilevel waveform @var{A} using histogram method INPUTS: @table @var @item A Bylevel waveform @item nbins Number of histogram bins (100 default) @item method State-level estimation method 'mode' (default) or 'mean'. @item bounds 2 element vector for histogram lower and upper bounds. Values outside of this will be ignored. @end table OUTPUTS: @table @var @item levels Levels of high and low states @item histograms Histogram counts @item binlevels Histogram bincenters @end table If no outputs are provided, the signal and histogram will be plotted, and display the levels. @end deftypefn @c --------------------------------------------------- @node Utility @section Utility @cindex Utility @c Utility buffer @c ----------------------------------------- @subsection buffer @cindex buffer @deftypefn {Function File} {@var{y} =} buffer (@var{x}, @var{n}, @var{p}, @var{opt}) @deftypefnx {Function File} {[@var{y}, @var{z}, @var{opt}] =} buffer (@dots{}) Buffer a signal into a data frame. The arguments to @code{buffer} are @table @asis @item @var{x} The data to be buffered. @item @var{n} The number of rows in the produced data buffer. This is an positive integer value and must be supplied. @item @var{p} An integer less than @var{n} that specifies the under- or overlap between column in the data frame. The default value of @var{p} is 0. @item @var{opt} In the case of an overlap, @var{opt} can be either a vector of length @var{p} or the string 'nodelay'. If @var{opt} is a vector, then the first @var{p} entries in @var{y} will be filled with these values. If @var{opt} is the string 'nodelay', then the first value of @var{y} corresponds to the first value of @var{x}. In the can of an underlap, @var{opt} must be an integer between 0 and @code{-@var{p}}. The represents the initial underlap of the first column of @var{y}. The default value for @var{opt} the vector @code{zeros (1, @var{p})} in the case of an overlap, or 0 otherwise. @end table In the case of a single output argument, @var{y} will be padded with zeros to fill the missing values in the data frame. With two output arguments @var{z} is the remaining data that has not been used in the current data frame. Likewise, the output @var{opt} is the overlap, or underlap that might be used for a future call to @code{code} to allow continuous buffering. @end deftypefn @c Utility clustersegment @c ----------------------------------------- @subsection clustersegment @cindex clustersegment @deftypefn {Function File} {@var{clusteridx} =} clustersegment (@var{unos}) Calculate boundary indexes of clusters of 1's. The function calculates the initial index and end index of the sequences of 1's in the rows of @var{unos}. The clusters are sought in the rows of the array @var{unos}. The result is returned in a cell array of size 1-by-@var{Np}, where @var{Np} is the number of rows in @var{unos}. Each element of the cell has two rows. The first row is the initial index of a sequence of 1's and the second row is the end index of that sequence. If @var{Np} == 1 the output is a matrix with two rows. The function works by finding the indexes of jumps between consecutive values in the rows of @var{unos}. @end deftypefn @c Utility fracshift @c ----------------------------------------- @subsection fracshift @cindex fracshift @deftypefn {Function File} {[@var{y}, @var{h}] =} fracshift (@var{x}, @var{d}) @deftypefnx {Function File} {@var{y} =} fracshift (@var{x}, @var{d}, @var{h}) Shift the series @var{x} by a (possibly fractional) number of samples @var{d}. The interpolator @var{h} is either specified or either designed with a Kaiser-windowed sinecard. @xseealso{circshift} @end deftypefn @c Utility marcumq @c ----------------------------------------- @subsection marcumq @cindex marcumq @deftypefn {Function File} {@var{q} =} marcumq (@var{a}, @var{b}) @deftypefnx {Function File} {@var{q} =} marcumq (@var{a}, @var{b}, @var{m}) @deftypefnx {Function File} {@var{q} =} marcumq (@var{a}, @var{b}, @var{m}, @var{tol}) Compute the generalized Marcum Q function of order @var{m} with noncentrality parameter @var{a} and argument @var{b}. If the order @var{m} is omitted it defaults to 1. An optional relative tolerance @var{tol} may be included, the default is @code{eps}. If the input arguments are commensurate vectors, this function will produce a table of values. This function computes Marcum's Q function using the infinite Bessel series, truncated when the relative error is less than the specified tolerance. The accuracy is limited by that of the Bessel functions, so reducing the tolerance is probably not useful. Reference: Marcum, "Tables of Q Functions", Rand Corporation. Reference: R.T. Short, "Computation of Noncentral Chi-squared and Rice Random Variables", www.phaselockedsystems.com/publications @end deftypefn @c Utility primitive @c ----------------------------------------- @subsection primitive @cindex primitive @deftypefn {Function File} {@var{F} =} primitive (@var{f}, @var{t}, @var{F0}) Calculate the primitive of a function. The function approximates the primitive (indefinite integral) of the univariate function handle @var{f} with constant of integration @var{F0}. The output is the primitive evaluated at the points @var{t}. The vector @var{t} must be ordered and ascending. This function is a fancy way of calculating the cumulative sum, @command{F = cumsum (f(t).*diff (t)([1 1:end]))}. Example: @example @group f = @@(t) sin (2 * pi * 3 * t); t = [0; sort(rand (100, 1))]; F = primitive (f, t, 0); t_true = linspace (0, 1, 1e3).'; F_true = (1 - cos (2 * pi * 3 * t_true)) / (2 * pi * 3); plot (t, F, 'o', t_true, F_true); @end group @end example @xseealso{quadgk, cumsum} @end deftypefn @c Utility sampled2continuous @c ----------------------------------------- @subsection sampled2continuous @cindex sampled2continuous @deftypefn {Function File} {@var{xt} =} sampled2continuous (@var{xn}, @var{T}, @var{t}) Calculate the x(t) reconstructed from samples x[n] sampled at a rate 1/T samples per unit time. t is all the instants of time when you need x(t) from x[n]; this time is relative to x[0] and not an absolute time. This function can be used to calculate sampling rate effects on aliasing, actual signal reconstruction from discrete samples. @end deftypefn @c Utility schtrig @c ----------------------------------------- @subsection schtrig @cindex schtrig @deftypefn {@var{v} =} schtrig (@var{x},@var{lvl},@var{rst}=1) @deftypefnx {[@var{v},@var{rng}] =} schtrig (@dots{}) Implements a multisignal Schmitt trigger with levels @var{lvl}. The triger works along the first dimension of the 2-dimensional array @var{x}. It compares each column in @var{x} to the levels in @var{lvl}, when the value is higher @code{max (@var{lvl})} the output @var{v} is high (i.e. 1); when the value is below @code{min (@var{lvl})} the output is low (i.e. 0); and when the value is between the two levels the output retains its value. The threshold levels are passed in the array @var{lvl}. If this is a scalar, the thresholds are symmetric around 0, i.e. @code{[-lvl lvl]}. The second output argument stores the ranges in which the output is high, so the indexes @var{rng(1,i):rng(2,i)} point to the i-th segment of 1s in @var{v}. See @code{clustersegment} for a detailed explanation. The function conserves the state of the trigger across calls (persistent variable). If the reset flag is active, i.e. @code{@var{rst}== true}, then the state of the trigger for all signals is set to the low state (i.e. 0). Example: @example x = [0 0.5 1 1.5 2 1.5 1.5 1.2 1 0 0].'; y = schtrig (x, [1.3 1.6]); disp ([x y]); 0.0 0 0.5 0 1.0 0 1.5 0 2.0 1 1.5 1 1.5 1 1.2 0 1.0 0 0.0 0 0.0 0 @end example Run @code{demo schtrig} to see further examples. @xseealso{clustersegment} @end deftypefn @c Utility upsamplefill @c ----------------------------------------- @subsection upsamplefill @cindex upsamplefill @deftypefn {Function File} {@var{y} =} upsamplefill (@var{x}, @var{v}) @deftypefnx {Function File} {@var{y} =} upsamplefill (@dots{}, @var{copy}) Upsamples a vector interleaving given values or copies of the vector elements. The values in the vector @var{v} are placed between the elements of @var{x}. If the optional argument @var{copy} is @var{true} then @var{v} should be a scalar and each value in @var{x} are repeat @var{v} times. Example: @example @group upsamplefill (eye (2), 2, true) @result{} 1 0 1 0 1 0 0 1 0 1 0 1 upsamplefill (eye (2), [-1 -1 -1]) @result{} 1 0 -1 -1 -1 -1 -1 -1 0 1 -1 -1 -1 -1 -1 -1 @end group @end example @xseealso{upsample} @end deftypefn @c Utility wkeep @c ----------------------------------------- @subsection wkeep @cindex wkeep @deftypefn {Function File} {@var{y} =} wkeep (@var{x}, @var{l}) @deftypefnx {Function File} {@var{y} =} wkeep (@var{x}, @var{l}, @var{opt}) Extract the elements of @var{x} of size @var{l} from the center, the right or the left. @end deftypefn @c Utility wrev @c ----------------------------------------- @subsection wrev @cindex wrev @deftypefn {Function File} {@var{y} =} wrev (@var{x}) Reverse the order of the element of the vector @var{x}. @xseealso{flipud, fliplr} @end deftypefn @c Utility zerocrossing @c ----------------------------------------- @subsection zerocrossing @cindex zerocrossing @deftypefn {Function File} {@var{x0} =} zerocrossing (@var{x}, @var{y}) Estimates the points at which a given waveform y=y(x) crosses the x-axis using linear interpolation. @xseealso{fzero, roots} @end deftypefn signal-1.4.5/doc/gpl.texi0000644000000000000000000010433014456505401013413 0ustar0000000000000000@node Copying @appendix GNU General Public License @cindex warranty @cindex copyright @center Version 3, 29 June 2007 @display Copyright @copyright{} 2007 Free Software Foundation, Inc. @url{http://fsf.org/} Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @end display @heading Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program---to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. @heading TERMS AND CONDITIONS @enumerate 0 @item Definitions. ``This License'' refers to version 3 of the GNU General Public License. ``Copyright'' also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. ``The Program'' refers to any copyrightable work licensed under this License. Each licensee is addressed as ``you''. ``Licensees'' and ``recipients'' may be individuals or organizations. To ``modify'' a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a ``modified version'' of the earlier work or a work ``based on'' the earlier work. A ``covered work'' means either the unmodified Program or a work based on the Program. To ``propagate'' a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To ``convey'' a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays ``Appropriate Legal Notices'' to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. @item Source Code. The ``source code'' for a work means the preferred form of the work for making modifications to it. ``Object code'' means any non-source form of a work. A ``Standard Interface'' means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The ``System Libraries'' of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A ``Major Component'', in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The ``Corresponding Source'' for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. @item Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. @item Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. @item Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. @item Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: @enumerate a @item The work must carry prominent notices stating that you modified it, and giving a relevant date. @item The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to ``keep intact all notices''. @item You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. @item If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. @end enumerate A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an ``aggregate'' if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. @item Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: @enumerate a @item Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. @item Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. @item Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. @item Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. @item Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. @end enumerate A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A ``User Product'' is either (1) a ``consumer product'', which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, ``normally used'' refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. ``Installation Information'' for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. @item Additional Terms. ``Additional permissions'' are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: @enumerate a @item Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or @item Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or @item Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or @item Limiting the use for publicity purposes of names of licensors or authors of the material; or @item Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or @item Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. @end enumerate All other non-permissive additional terms are considered ``further restrictions'' within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. @item Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. @item Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. @item Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An ``entity transaction'' is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. @item Patents. A ``contributor'' is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's ``contributor version''. A contributor's ``essential patent claims'' are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, ``control'' includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a ``patent license'' is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To ``grant'' such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. ``Knowingly relying'' means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is ``discriminatory'' if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. @item No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. @item Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. @item Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License ``or any later version'' applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. @item Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. @item Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. @item Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. @end enumerate @heading END OF TERMS AND CONDITIONS @heading How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the ``copyright'' line and a pointer to where the full notice is found. @smallexample @var{one line to give the program's name and a brief idea of what it does.} Copyright (C) @var{year} @var{name of author} This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see @url{http://www.gnu.org/licenses/}. @end smallexample Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: @smallexample @var{program} Copyright (C) @var{year} @var{name of author} This program comes with ABSOLUTELY NO WARRANTY; for details type @samp{show w}. This is free software, and you are welcome to redistribute it under certain conditions; type @samp{show c} for details. @end smallexample The hypothetical commands @samp{show w} and @samp{show c} should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an ``about box''. You should also get your employer (if you work as a programmer) or school, if any, to sign a ``copyright disclaimer'' for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see @url{http://www.gnu.org/licenses/}. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read @url{http://www.gnu.org/philosophy/why-not-lgpl.html}. signal-1.4.5/doc/macros.texi0000644000000000000000000000624114456505401014117 0ustar0000000000000000@c Copyright (C) 2012-2019 John W. Eaton @c @c This file is part of Octave. @c @c Octave is free software: you can redistribute it and/or modify it @c under the terms of the GNU General Public License as published by @c the Free Software Foundation, either version 3 of the License, or @c (at your option) any later version. @c @c Octave is distributed in the hope that it will be useful, but @c WITHOUT ANY WARRANTY; without even the implied warranty of @c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @c GNU General Public License for more details. @c @c You should have received a copy of the GNU General Public License @c along with Octave; see the file COPYING. If not, see @c . @c The following macro marks words that aspell should ignore during @c spellchecking. Within Texinfo it has no effect as it merely replaces @c the macro call with the argument itself. @macro nospell {arg} \arg\ @end macro @c The following macro works around the Info/plain text expansion of @code{XXX} @c which is `XXX'. This looks particularly bad when the macro body is @c single or double-quoted text, such as a property value `"position"' @ifinfo @macro qcode{arg} \arg\ @end macro @end ifinfo @ifnotinfo @macro qcode{arg} @code{\arg\} @end macro @end ifnotinfo @c The following macro is used for the on-line help system, but we don't @c want lots of `See also: foo, bar, and baz' strings cluttering the @c printed manual (that information should be in the supporting text for @c each group of functions and variables). @c @c Implementation Note: @c For TeX, @vskip produces a nice separation. @c For Texinfo, '@sp 1' should work, but in practice produces ugly results @c for HTML. We use a simple blank line to produce the correct @c behavior. @c @c We use @xseealso now because Texinfo introduced its own @seealso @c command. But instead of modifying all source files, we'll have the @c munge-texi script convert @seealso to @xseealso. @macro xseealso {args} @iftex @vskip 2pt @end iftex @ifnottex @end ifnottex @ifnotinfo @noindent @strong{See also:} \args\. @end ifnotinfo @ifinfo @noindent See also: \args\. @end ifinfo @end macro @c The following macro works around a situation where the Info/plain text @c expansion of the @code{XXX} macro is `XXX'. The use of the apostrophe @c can be confusing if the code segment itself ends with a transpose operator. @ifinfo @macro tcode{arg} \arg\ @end macro @end ifinfo @ifnotinfo @macro tcode{arg} @code{\arg\} @end macro @end ifnotinfo @c FIXME: someday, when Texinfo 5.X is standard, we might replace this with @c @backslashchar, which is a new addition to Texinfo. @macro xbackslashchar \\ @end macro @c These may be useful for all, not just for octave.texi. @tex \ifx\rgbDarkRed\thisisundefined \def\rgbDarkRed{0.50 0.09 0.12} \fi \ifx\linkcolor\thisisundefined \relax \else \global\def\linkcolor{\rgbDarkRed} \fi \ifx\urlcolor\thisisundefined \relax \else \global\def\urlcolor{\rgbDarkRed} \fi \ifx\urefurlonlylinktrue\thisisundefined \relax \else \global\urefurlonlylinktrue \fi @end tex @c Make the apostrophe in code examples cut-and-paste friendly. @codequoteundirected on signal-1.4.5/doc/signal.css0000644000000000000000000000133714456505401013730 0ustar0000000000000000pre.example, .header, .float-caption, hr { /* base00 ~ body text in light solarized theme */ color: #657b83; border-color: #657b83; } pre.example { /* base3 ~ background color in light solarized theme */ background-color: #fdf6e3; padding: 0.5em; } table.cartouche { border: 1px solid #948473; background-color: #FFE3C6; width: 100%; } table.cartouche td, table.cartouche th { border: 1px solid #948473; padding: 4px 4px; } /* newer texinfo generation styles */ div.example { /* base00 ~ body text in light solarized theme */ color: #657b83; border-color: #657b83; } pre.example-preformatted { /* base3 ~ background color in light solarized theme */ background-color: #fdf6e3; padding: 0.5em; } signal-1.4.5/doc/signal.info0000644000000000000000000056165614456505401014112 0ustar0000000000000000This is signal.info, produced by makeinfo version 7.0.2 from signal.texi. INFO-DIR-SECTION Math START-INFO-DIR-ENTRY * Octave Signal: (signal). Signal Toolkit for Octave END-INFO-DIR-ENTRY  File: signal.info, Node: Top, Next: Overview, Up: (dir) Octave Signal Toolkit ********************* Copyright © The Octave Project Developers Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions. * Menu: * Overview:: * Installing and loading:: * Function Reference::  File: signal.info, Node: Overview, Next: Installing and loading, Prev: Top, Up: Top 1 Overview ********** The Signal Toolkit contains signal processing tools, including filtering, windowing and display functions.  File: signal.info, Node: Installing and loading, Next: Function Reference, Prev: Overview, Up: Top 2 Installing and loading ************************ The Signal Toolkit must be installed and then loaded to be used. It can be installed in GNU Octave directly from octave-forge, 2.1 Windows install =================== If running in Windows, the package may already be installed, to check run: pkg list signal 2.2 Installing ============== With an internet connection available, the Signal package can be installed from octave-forge using the following command within GNU Octave: pkg install -forge signal The latest released version of the toolkit will be downloaded and installed. Otherwise, if the package file has already been downloaded it can be installed using the follwoing command in GNU Octave: pkg install signal-1.4.5.tar.gz 2.3 Loading =========== Regardless of the method of installing the toolkit, in order to use its functions, the toolkit must be loaded using the pkg load command: pkg load signal The toolkit must be loaded on each GNU Octave session.  File: signal.info, Node: Function Reference, Prev: Installing and loading, Up: Top 3 Function Reference ******************** * Menu: * Signals:: * Signal Measurement:: * Correlation and Convolution:: * Filtering:: * Filter Analysis:: * Filter Conversion:: * IIR Filter Design:: * FIR Filter Design:: * Transforms:: * Power Spectrum Analysis:: * Window Functions:: * System Identification:: * Sample Rate Change:: * Pulse Metrics:: * Utility::  File: signal.info, Node: Signals, Next: Signal Measurement, Up: Function Reference 3.1 Signals =========== 3.1.1 buffer ------------ -- Function File: Y = buffer (X, N, P, OPT) -- Function File: [Y, Z, OPT] = buffer (...) Buffer a signal into a data frame. The arguments to ‘buffer’ are X The data to be buffered. N The number of rows in the produced data buffer. This is an positive integer value and must be supplied. P An integer less than N that specifies the under- or overlap between column in the data frame. The default value of P is 0. OPT In the case of an overlap, OPT can be either a vector of length P or the string ’nodelay’. If OPT is a vector, then the first P entries in Y will be filled with these values. If OPT is the string ’nodelay’, then the first value of Y corresponds to the first value of X. In the can of an underlap, OPT must be an integer between 0 and ‘-P’. The represents the initial underlap of the first column of Y. The default value for OPT the vector ‘zeros (1, P)’ in the case of an overlap, or 0 otherwise. In the case of a single output argument, Y will be padded with zeros to fill the missing values in the data frame. With two output arguments Z is the remaining data that has not been used in the current data frame. Likewise, the output OPT is the overlap, or underlap that might be used for a future call to ‘code’ to allow continuous buffering. 3.1.2 chirp ----------- -- Function File: chirp (T) -- Function File: chirp (T, F0) -- Function File: chirp (T, F0, T1) -- Function File: chirp (T, F0, T1, F1) -- Function File: chirp (T, F0, T1, F1, SHAPE) -- Function File: chirp (T, F0, T1, F1, SHAPE, PHASE) Evaluate a chirp signal at time T. A chirp signal is a frequency swept cosine wave. T vector of times to evaluate the chirp signal F0 frequency at time t=0 [ 0 Hz ] T1 time t1 [ 1 sec ] F1 frequency at time t=t1 [ 100 Hz ] SHAPE shape of frequency sweep ’linear’ f(t) = (f1-f0)*(t/t1) + f0 ’quadratic’ f(t) = (f1-f0)*(t/t1)^2 + f0 ’logarithmic’ f(t) = (f1/f0)^(t/t1) * f0 PHASE phase shift at t=0 For example: specgram (chirp ([0:0.001:5])); # default linear chirp of 0-100Hz in 1 sec specgram (chirp ([-2:0.001:15], 400, 10, 100, "quadratic")); soundsc (chirp ([0:1/8000:5], 200, 2, 500, "logarithmic"), 8000); If you want a different sweep shape f(t), use the following: y = cos (2 * pi * integral (f(t)) + phase); 3.1.3 cmorwavf -------------- -- Function File: [PSI, X] = cmorwavf (LB, UB, N, FB, FC) Compute the Complex Morlet wavelet. 3.1.4 diric ----------- -- Function File: Y = diric (X,N) Compute the dirichlet function. See also: sinc, gauspuls, sawtooth. 3.1.5 gauspuls -------------- -- Function File: Y = gauspuls (T) -- Function File: Y = gauspuls (T, FC) -- Function File: Y = gauspuls (T, FC, BW) Generate a Gaussian modulated sinusoidal pulse sampled at times T. See also: pulstran, rectpuls, tripuls. 3.1.6 gmonopuls --------------- -- Function File: Y = gmonopuls (T,FC) Return the gaussian monopulse. 3.1.7 mexihat ------------- -- Function File: [PSI, X] = mexihat (LB, UB, N) Compute the Mexican hat wavelet. 3.1.8 meyeraux -------------- -- Function File: Y = meyeraux (X) Compute the Meyer wavelet auxiliary function. 3.1.9 morlet ------------ -- Function File: [PSI, X] = morlet (LB, UB, N) Compute the Morlet wavelet. 3.1.10 pulstran --------------- -- Function File: Y = pulstran (T, D, FUNC, ...) -- Function File: Y = pulstran (T, D, P) -- Function File: Y = pulstran (T, D, P, FS) -- Function File: Y = pulstran (T, D, P, FS, METHOD) Generate the signal y=sum(func(t+d,...)) for each d. If d is a matrix of two columns, the first column is the delay d and the second column is the amplitude a, and y=sum(a*func(t+d)) for each d,a. Clearly, func must be a function which accepts a vector of times. Any extra arguments needed for the function must be tagged on the end. Example: fs = 11025; # arbitrary sample rate f0 = 100; # pulse train sample rate w = 0.001; # pulse width of 1 millisecond auplot (pulstran (0:1/fs:0.1, 0:1/f0:0.1, "rectpuls", w), fs); If instead of a function name you supply a pulse shape sampled at frequency Fs (default 1 Hz), an interpolated version of the pulse is added at each delay d. The interpolation stays within the the time range of the delayed pulse. The interpolation method defaults to linear, but it can be any interpolation method accepted by the function interp1. Example: fs = 11025; # arbitrary sample rate f0 = 100; # pulse train sample rate w = boxcar(10); # pulse width of 1 millisecond at 10 kHz auplot (pulstran (0:1/fs:0.1, 0:1/f0:0.1, w, 10000), fs); 3.1.11 rectpuls --------------- -- Function File: Y = rectpuls (T) -- Function File: Y = rectpuls (T, W) Generate a rectangular pulse over the interval [-W/2,W/2), sampled at times T. This is useful with the function ‘pulstran’ for generating a series of pulses. Example: fs = 11025; # arbitrary sample rate f0 = 100; # pulse train sample rate w = 0.3/f0; # pulse width 3/10th the distance between pulses plot (pulstran (0:1/fs:4/f0, 0:1/f0:4/f0, "rectpuls", w)); See also: gauspuls, pulstran, tripuls. 3.1.12 sawtooth --------------- -- Function File: Y = sawtooth (T) -- Function File: Y = sawtooth (T, WIDTH) Generates a sawtooth wave of period ‘2 * pi’ with limits ‘+1/-1’ for the elements of T. WIDTH is a real number between ‘0’ and ‘1’ which specifies the point between ‘0’ and ‘2 * pi’ where the maximum is. The function increases linearly from ‘-1’ to ‘1’ in ‘[0, 2 * pi * WIDTH]’ interval, and decreases linearly from ‘1’ to ‘-1’ in the interval ‘[2 * pi * WIDTH, 2 * pi]’. If WIDTH is 0.5, the function generates a standard triangular wave. If WIDTH is not specified, it takes a value of 1, which is a standard sawtooth function. 3.1.13 shanwavf --------------- -- Function File: [PSI, X] = shanwavf (LB, UB, N, FB, FC) Compute the Complex Shannon wavelet. 3.1.14 shiftdata ---------------- -- Function File: [OUT PERM SHIFTS] = shiftdata (IN) -- Function File: [OUT PERM SHIFTS] = shiftdata (IN, DIM) Shift data IN to permute the dimension DIM to the first column. See also: unshiftdata. 3.1.15 sigmoid_train -------------------- -- Function File: [Y S] = sigmoid_train (T, RANGES, RC) Evaluate a train of sigmoid functions at T. The number and duration of each sigmoid is determined from RANGES. Each row of RANGES represents a real interval, e.g. if sigmoid ‘i’ starts at ‘t=0.1’ and ends at ‘t=0.5’, then ‘RANGES(i,:) = [0.1 0.5]’. The input RC is an array that defines the rising and falling time constants of each sigmoid. Its size must equal the size of RANGES. The individual sigmoids are returned in S. The combined sigmoid train is returned in the vector Y of length equal to T, and such that ‘Y = max (S)’. Run ‘demo sigmoid_train’ to some examples of the use of this function. 3.1.16 specgram --------------- -- Function File: specgram (X) -- Function File: specgram (X, N) -- Function File: specgram (X, N, FS) -- Function File: specgram (X, N, FS, WINDOW) -- Function File: specgram (X, N, FS, WINDOW, OVERLAP) -- Function File: [S, F, T] = specgram (...) Generate a spectrogram for the signal X. The signal is chopped into overlapping segments of length N, and each segment is windowed and transformed into the frequency domain using the FFT. The default segment size is 256. If FS is given, it specifies the sampling rate of the input signal. The argument WINDOW specifies an alternate window to apply rather than the default of ‘hanning (N)’. The argument OVERLAP specifies the number of samples overlap between successive segments of the input signal. The default overlap is ‘length (WINDOW)/2’. If no output arguments are given, the spectrogram is displayed. Otherwise, S is the complex output of the FFT, one row per slice, F is the frequency indices corresponding to the rows of S, and T is the time indices corresponding to the columns of S. Example: x = chirp([0:0.001:2],0,2,500); # freq. sweep from 0-500 over 2 sec. Fs=1000; # sampled every 0.001 sec so rate is 1 kHz step=ceil(20*Fs/1000); # one spectral slice every 20 ms window=ceil(100*Fs/1000); # 100 ms data window specgram(x, 2^nextpow2(window), Fs, window, window-step); ## Speech spectrogram [x, Fs] = auload(file_in_loadpath("sample.wav")); # audio file step = fix(5*Fs/1000); # one spectral slice every 5 ms window = fix(40*Fs/1000); # 40 ms data window fftn = 2^nextpow2(window); # next highest power of 2 [S, f, t] = specgram(x, fftn, Fs, window, window-step); S = abs(S(2:fftn*4000/Fs,:)); # magnitude in range 0= minF & f <= maxF); Then there is the choice of colormap. A brightness varying colormap such as copper or bone gives good shape to the ridges and valleys. A hue varying colormap such as jet or hsv gives an indication of the steepness of the slopes. The final spectrogram is displayed in log energy scale and by convention has low frequencies on the bottom of the image: imagesc(t, f, flipud(log(S(idx,:)))); 3.1.17 square ------------- -- Function File: S = square (T, DUTY) -- Function File: S = square (T) Generate a square wave of period 2 pi with limits +1/-1. If DUTY is specified, it is the percentage of time the square wave is "on". The square wave is +1 for that portion of the time. on time * 100 duty cycle = ------------------ on time + off time See also: cos, sawtooth, sin, tripuls. 3.1.18 tripuls -------------- -- Function File: Y = tripuls (T) -- Function File: Y = tripuls (T, W) -- Function File: Y = tripuls (T, W, SKEW) Generate a triangular pulse over the interval [-W/2,W/2), sampled at times T. This is useful with the function ‘pulstran’ for generating a series of pulses. SKEW is a value between -1 and 1, indicating the relative placement of the peak within the width. -1 indicates that the peak should be at -W/2, and 1 indicates that the peak should be at W/2. The default value is 0. Example: fs = 11025; # arbitrary sample rate f0 = 100; # pulse train sample rate w = 0.3/f0; # pulse width 3/10th the distance between pulses plot (pulstran (0:1/fs:4/f0, 0:1/f0:4/f0, "tripuls", w)); See also: gauspuls, pulstran, rectpuls. 3.1.19 udecode -------------- -- Function File: OUT = udecode (IN, N) -- Function File: OUT = udecode (IN, N, V) -- Function File: OUT = udecode (IN, N, V, OVERFLOWS) Invert the operation of uencode. See also: uencode. 3.1.20 uencode -------------- -- Function File: OUT = uencode (IN, N) -- Function File: OUT = uencode (IN, N, V) -- Function File: OUT = uencode (IN, N, V, SIGNED) Quantize the entries of the array IN using 2^N quantization levels. See also: udecode. 3.1.21 unshiftdata ------------------ -- Function File: [OUT] = unshiftdata (IN, PERM, SHIFTS) Reverse what is done by shiftdata. See also: shiftdata. 3.1.22 vco ---------- -- : y = vco (X, FC, FS) -- : y = vco (X, [FMIN, FMAX], FS) Creates a signal that oscillates at a frequency determined by input X with a sampling frequency FS. Inputs: • X - input data with a range of -1 to 1. A value of -1 means no output, 0 cuoreesponds to FC, and 1 corresponds to 2*FC. • FC - Carrier frequency • FS - Sampling rate • FMIN, FMAX - Frequency modulation range limits. Outputs: • Y - output signal  File: signal.info, Node: Signal Measurement, Next: Correlation and Convolution, Prev: Signals, Up: Function Reference 3.2 Signal Measurement ====================== 3.2.1 findpeaks --------------- -- Function File: [PKS, LOC, EXTRA] = findpeaks (DATA) -- Function File: ... = findpeaks (..., PROPERTY, VALUE) -- Function File: ... = findpeaks (..., "DoubleSided") Finds peaks on DATA. Peaks of a positive array of data are defined as local maxima. For double-sided data, they are maxima of the positive part and minima of the negative part. DATA is expected to be a single column vector. The function returns the value of DATA at the peaks in PKS. The index indicating their position is returned in LOC. The third output argument is a structure with additional information: "parabol" A structure containing the parabola fitted to each returned peak. The structure has two fields, "x" and "pp". The field "pp" contains the coefficients of the 2nd degree polynomial and "x" the extrema of the interval where it was fitted. "height" The estimated height of the returned peaks (in units of DATA). "baseline" The height at which the roots of the returned peaks were calculated (in units of DATA). "roots" The abscissa values (in index units) at which the parabola fitted to each of the returned peaks realizes its width as defined below. This function accepts property-value pair given in the list below: "MinPeakHeight" Minimum peak height (non-negative scalar). Only peaks that exceed this value will be returned. For data taking positive and negative values use the option "DoubleSided". Default value ‘eps’. "MinPeakDistance" Minimum separation between (positive integer). Peaks separated by less than this distance are considered a single peak. This distance is also used to fit a second order polynomial to the peaks to estimate their width, therefore it acts as a smoothing parameter. The neighborhood size is equal to the value of "MinPeakDistance". Default value 1. "MinPeakWidth" Minimum width of peaks (positive integer). The width of the peaks is estimated using a parabola fitted to the neighborhood of each peak. The width is caulculated with the formula a * (width - x0)^2 = 1 where a is the the concavity of the parabola and x0 its vertex. Default value 1. "MaxPeakWidth" Maximum width of peaks (positive integer). Default value ‘Inf’. "DoubleSided" Tells the function that data takes positive and negative values. The base-line for the peaks is taken as the mean value of the function. This is equivalent as passing the absolute value of the data after removing the mean. Run ‘demo findpeaks’ to see some examples. 3.2.2 peak2peak --------------- -- Function File: Y = peak2peak (X) -- Function File: Y = peak2peak (X, DIM) Compute the difference between the maximum and minimum values in the vector X. If X is a matrix, compute the difference for each column and return them in a row vector. If the optional argument DIM is given, operate along this dimension. See also: max, min, peak2rms, rms, rssq. 3.2.3 peak2rms -------------- -- Function File: Y = peak2rms (X) -- Function File: Y = peak2rms (X, DIM) Compute the ratio of the largest absolute value to the root-mean-square (RMS) value of the vector X. If X is a matrix, compute the peak-magnitude-to-RMS ratio for each column and return them in a row vector. If the optional argument DIM is given, operate along this dimension. See also: max, min, peak2peak, rms, rssq. 3.2.4 rms --------- -- Function File: Y = rms (X) -- Function File: Y = rms (X, DIM) Compute the root-mean-square (RMS) of the vector X. The root-mean-square is defined as rms (X) = SQRT (1/N SUM_i X(i)^2) If X is a matrix, compute the root-mean-square for each column and return them in a row vector. If the optional argument DIM is given, operate along this dimension. See also: mean, meansq, peak2rms, rssq, sumsq. 3.2.5 rssq ---------- -- Function File: Y = rssq (X) -- Function File: Y = rssq (X, DIM) Compute the root-sum-of-squares (RSS) of the vector X. The root-sum-of-squares is defined as rssq (X) = SQRT (SUM_i X(i)^2) If X is a matrix, compute the root-sum-of-squares for each column and return them in a row vector. If the optional argument DIM is given, operate along this dimension. See also: mean, meansq, sumsq, rms.  File: signal.info, Node: Correlation and Convolution, Next: Filtering, Prev: Signal Measurement, Up: Function Reference 3.3 Correlation and Convolution =============================== 3.3.1 cconv ----------- -- Function File: C = cconv (A, B, N) -- Function File: C = cconv (A, B) Compute the modulo-N circular convolution. A and B are input vectors and C is the modolo-N convolution of A and B. If N is not provided, its assumed default value is ‘length(A) + length(B) - 1’, which provides the same result as a linear convolution. Examples: cconv (1:2, 1:4) ⇒ 1 4 7 10 8 cconv (1:2, 1:4, 2) ⇒ 16 14 cconv (1:2, 1:4, 4) ⇒ 9 4 7 10 See also: conv, circshift. 3.3.2 convmtx ------------- -- Function File: convmtx (A, N) If A is a column vector and X is a column vector of length N, then ‘convmtx(A, N) * X’ gives the convolution of of A and X and is the same as ‘conv(A, X)’. The difference is if many vectors are to be convolved with the same vector, then this technique is possibly faster. Similarly, if A is a row vector and X is a row vector of length N, then ‘X * convmtx(A, N)’ is the same as ‘conv(X, A)’. See also: conv. 3.3.3 wconv ----------- -- Function File: Y = wconv (TYPE, X, F) -- Function File: Y = wconv (TYPE, X, F, SHAPE) 1-D or 2-D convolution. *Inputs* TYPE Type of convolution. X Signal vector or matrix. F Coefficients of FIR filter. SHAPE Shape. *Outputs* Y Convoluted signal. 3.3.4 xcorr ----------- -- Function File: [R, LAG] = xcorr ( X ) -- Function File: ... = xcorr ( X, Y ) -- Function File: ... = xcorr ( ..., MAXLAG) -- Function File: ... = xcorr ( ..., SCALE) Estimates the cross-correlation. Estimate the cross correlation R_xy(k) of vector arguments X and Y or, if Y is omitted, estimate autocorrelation R_xx(k) of vector X, for a range of lags k specified by argument "maxlag". If X is a matrix, each column of X is correlated with itself and every other column. The cross-correlation estimate between vectors "x" and "y" (of length N) for lag "k" is given by N R_xy(k) = sum x_{i+k} conj(y_i), i=1 where data not provided (for example x(-1), y(N+1)) is zero. Note the definition of cross-correlation given above. To compute a cross-correlation consistent with the field of statistics, see ‘xcov’. *ARGUMENTS* X [non-empty; real or complex; vector or matrix] data Y [real or complex vector] data If X is a matrix (not a vector), Y must be omitted. Y may be omitted if X is a vector; in this case xcorr estimates the autocorrelation of X. MAXLAG [integer scalar] maximum correlation lag If omitted, the default value is N-1, where N is the greater of the lengths of X and Y or, if X is a matrix, the number of rows in X. SCALE [character string] specifies the type of scaling applied to the correlation vector (or matrix). is one of: ‘none’ return the unscaled correlation, R, ‘biased’ return the biased average, R/N, ‘unbiased’ return the unbiased average, R(k)/(N-|k|), ‘coeff or normalized’ return the correlation coefficient, R/(rms(x).rms(y)), where "k" is the lag, and "N" is the length of X. If omitted, the default value is "none". If Y is supplied but does not have the same length as X, scale must be "none". *RETURNED VARIABLES* R array of correlation estimates LAG row vector of correlation lags [-maxlag:maxlag] The array of correlation estimates has one of the following forms: (1) Cross-correlation estimate if X and Y are vectors. (2) Autocorrelation estimate if is a vector and Y is omitted. (3) If X is a matrix, R is an matrix containing the cross-correlation estimate of each column with every other column. Lag varies with the first index so that R has 2*maxlag+1 rows and P^2 columns where P is the number of columns in X. If Rij(k) is the correlation between columns i and j of X ‘R(k+maxlag+1,P*(i-1)+j) == Rij(k)’ for lag k in [-maxlag:maxlag], or ‘R(:,P*(i-1)+j) == xcorr(X(:,i),X(:,j))’. ‘reshape(R(k,:),P,P)’ is the cross-correlation matrix for ‘X(k,:)’. See also: xcov. 3.3.5 xcorr2 ------------ -- Function File: xcorr2 (A) -- Function File: xcorr2 (A, B) -- Function File: xcorr2 (..., SCALE) Compute the 2D cross-correlation of matrices A and B. If B is not specified, computes autocorrelation of A, i.e., same as ‘xcorr (A, A)’. The optional argument SCALE, defines the type of scaling applied to the cross-correlation matrix. Possible values are: "none" (default) No scaling. "biased" Scales the raw cross-correlation by the maximum number of elements of A and B involved in the generation of any element of C. "unbiased" Scales the raw correlation by dividing each element in the cross-correlation matrix by the number of products A and B used to generate that element. "coeff" Scales the normalized cross-correlation on the range of [0 1] so that a value of 1 corresponds to a correlation coefficient of 1. See also: conv2, corr2, xcorr. 3.3.6 xcov ---------- -- Function File: [R, LAG] = xcov ( X ) -- Function File: ... = xcov ( X, Y ) -- Function File: ... = xcov ( ..., MAXLAG) -- Function File: ... = xcov ( ..., SCALE) Compute covariance at various lags [=correlation(x-mean(x),y-mean(y))]. X input vector Y if specified, compute cross-covariance between X and Y, otherwise compute autocovariance of X. MAXLAG is specified, use lag range [-maxlag:maxlag], otherwise use range [-n+1:n-1]. SCALE: ‘biased’ for covariance=raw/N, ‘unbiased’ for covariance=raw/(N-|lag|), ‘coeff’ for covariance=raw/(covariance at lag 0), ‘none’ for covariance=raw ‘none’ is the default. Returns the covariance for each lag in the range, plus an optional vector of lags. See also: xcorr.  File: signal.info, Node: Filtering, Next: Filter Analysis, Prev: Correlation and Convolution, Up: Function Reference 3.4 Filtering ============= 3.4.1 filtfilt -------------- -- Function File: Y = filtfilt (B, A, X) Forward and reverse filter the signal. This corrects for phase distortion introduced by a one-pass filter, though it does square the magnitude response in the process. That’s the theory at least. In practice the phase correction is not perfect, and magnitude response is distorted, particularly in the stop band. Example [b, a]=butter(3, 0.1); # 5 Hz low-pass filter t = 0:0.01:1.0; # 1 second sample x=sin(2*pi*t*2.3)+0.25*randn(size(t)); # 2.3 Hz sinusoid+noise y = filtfilt(b,a,x); z = filter(b,a,x); # apply filter plot(t,x,';data;',t,y,';filtfilt;',t,z,';filter;') 3.4.2 filtic ------------ -- Function File: ZF = filtic (B, A, Y) -- Function File: ZF = filtic (B, A, Y, X) Set initial condition vector for filter function The vector zf has the same values that would be obtained from function filter given past inputs x and outputs y The vectors x and y contain the most recent inputs and outputs respectively, with the newest values first: x = [x(-1) x(-2) ... x(-nb)], nb = length(b)-1 y = [y(-1) y(-2) ... y(-na)], na = length(a)-a If length(x) p. By default, p=3 and n=p+2 or n=p+3 if p is even. If F is given as a matrix, it is expected to be a filter as computed by ‘sgolay’. These filters are particularly good at preserving lineshape while removing high frequency squiggles. Particularly, compare a 5 sample averager, an order 5 butterworth lowpass filter (cutoff 1/3) and sgolayfilt(x, 3, 5), the best cubic estimated from 5 points: [b, a] = butter (5, 1/3); x = [zeros(1,15), 10*ones(1,10), zeros(1,15)]; plot (sgolayfilt (x), "r;sgolayfilt;", ... filtfilt (ones (1,5)/5, 1, x), "g;5 sample average;", ... filtfilt (b, a, x), "c;order 5 butterworth;", ... x, "+b;original data;"); See also: sgolay. 3.4.6 sosfilt ------------- -- Loadable Function: Y = sosfilt (SOS, X) Second order section IIR filtering of X. The second order section filter is described by the matrix SOS with: [ B1 A1 ] SOS = [ ... ], [ BN AN ] where ‘B1 = [b0 b1 b2]’ and ‘A1 = [1 a1 a2]’ for section 1, etc. The b0 entry must be nonzero for each section.  File: signal.info, Node: Filter Analysis, Next: Filter Conversion, Prev: Filtering, Up: Function Reference 3.5 Filter Analysis =================== 3.5.1 filternorm ---------------- -- Function File: L = filternorm (B, A) -- Function File: L = filternorm (B, A, PNORM) -- Function File: L = filternorm (B, A, 2, TOL) Compute the 2-norm of a digital filter defined by the numerator coefficients, B, and the denominator coefficients, A. It is also possible to compute the infinity-norm by passing inf in the PNORM parameter. PNORM only accepts 2 or inf. Example: [b, a] = butter (8, 0.5); filternorm (b, a) 3.5.2 filtord ------------- -- Function File: N = filtord (B, A) -- Function File: N = filtord (SOS) Returns the filter order N for a filter defined by the numerator coefficients, B, and the denominator coefficients, A. It also accepts a filter defined by a matrix of second-order sections, SOS. Example: [b, a] = butter (8, 0.5); filtord (b, a) 3.5.3 freqs ----------- -- Function File: H = freqs (B, A, W) -- Function File: freqs (B, A, W) Compute the s-plane frequency response of the IIR filter B(s)/A(s) as H = polyval(B,j*W)./polyval(A,j*W). If called with no output argument, a plot of magnitude and phase are displayed. Example: b = [1 2]; a = [1 1]; w = linspace (0, 4, 128); freqs (b, a, w); 3.5.4 freqs_plot ---------------- -- Function File: freqs_plot (W, H) Plot the amplitude and phase of the vector H. 3.5.5 fwhm ---------- -- Function File: F = fwhm (Y) -- Function File: F = fwhm (X, Y) -- Function File: F = fwhm (..., "zero") -- Function File: F = fwhm (..., "min") -- Function File: F = fwhm (..., "alevel", LEVEL) -- Function File: F = fwhm (..., "rlevel", LEVEL) Compute peak full-width at half maximum (FWHM) or at another level of peak maximum for vector or matrix data Y, optionally sampled as y(x). If Y is a matrix, return FWHM for each column as a row vector. The default option "zero" computes fwhm at half maximum, i.e. 0.5*max(y). The option "min" computes fwhm at the middle curve, i.e. 0.5*(min(y)+max(y)). The option "rlevel" computes full-width at the given relative level of peak profile, i.e. at rlevel*max(y) or rlevel*(min(y)+max(y)), respectively. For example, ‘fwhm (..., "rlevel", 0.1)’ computes full width at 10 % of peak maximum with respect to zero or minimum; FWHM is equivalent to ‘fwhm(..., "rlevel", 0.5)’. The option "alevel" computes full-width at the given absolute level of Y. Return 0 if FWHM does not exist (e.g. monotonous function or the function does not cut horizontal line at rlevel*max(y) or rlevel*(max(y)+min(y)) or alevel, respectively). 3.5.6 grpdelay -------------- -- Function File: [G, W] = grpdelay (B) -- Function File: [G, W] = grpdelay (B, A) -- Function File: [G, W] = grpdelay (..., N) -- Function File: [G, W] = grpdelay (..., N, "whole") -- Function File: [G, F] = grpdelay (..., N, FS) -- Function File: [G, F] = grpdelay (..., N, "whole", FS) -- Function File: [G, W] = grpdelay (..., W) -- Function File: [G, F] = grpdelay (..., F, FS) -- Function File: grpdelay (...) Compute the group delay of a filter. [g, w] = grpdelay(b) returns the group delay g of the FIR filter with coefficients b. The response is evaluated at 512 angular frequencies between 0 and pi. w is a vector containing the 512 frequencies. The group delay is in units of samples. It can be converted to seconds by multiplying by the sampling period (or dividing by the sampling rate fs). [g, w] = grpdelay(b,a) returns the group delay of the rational IIR filter whose numerator has coefficients b and denominator coefficients a. [g, w] = grpdelay(b,a,n) returns the group delay evaluated at n angular frequencies. For fastest computation n should factor into a small number of small primes. [g, w] = grpdelay(b,a,n,’whole’) evaluates the group delay at n frequencies between 0 and 2*pi. [g, f] = grpdelay(b,a,n,Fs) evaluates the group delay at n frequencies between 0 and Fs/2. [g, f] = grpdelay(b,a,n,’whole’,Fs) evaluates the group delay at n frequencies between 0 and Fs. [g, w] = grpdelay(b,a,w) evaluates the group delay at frequencies w (radians per sample). [g, f] = grpdelay(b,a,f,Fs) evaluates the group delay at frequencies f (in Hz). grpdelay(...) plots the group delay vs. frequency. If the denominator of the computation becomes too small, the group delay is set to zero. (The group delay approaches infinity when there are poles or zeros very close to the unit circle in the z plane.) Theory: group delay, g(w) = -d/dw [arg{H(e^jw)}], is the rate of change of phase with respect to frequency. It can be computed as: d/dw H(e^-jw) g(w) = ------------- H(e^-jw) where H(z) = B(z)/A(z) = sum(b_k z^k)/sum(a_k z^k). By the quotient rule, A(z) d/dw B(z) - B(z) d/dw A(z) d/dw H(z) = ------------------------------- A(z) A(z) Substituting into the expression above yields: A dB - B dA g(w) = ----------- = dB/B - dA/A A B Note that, d/dw B(e^-jw) = sum(k b_k e^-jwk) d/dw A(e^-jw) = sum(k a_k e^-jwk) which is just the FFT of the coefficients multiplied by a ramp. As a further optimization when nfft>>length(a), the IIR filter (b,a) is converted to the FIR filter conv(b,fliplr(conj(a))). For further details, see http://ccrma.stanford.edu/~jos/filters/Numerical_Computation_Group_Delay.html 3.5.7 impz ---------- -- Function File: [X, T] = impz (B) -- Function File: [X, T] = impz (B, A) -- Function File: [X, T] = impz (B, A, N) -- Function File: [X, T] = impz (B, A, N, FS) -- Function File: impz (...) Generate impulse-response characteristics of the filter. The filter coefficients correspond to the the z-plane rational function with numerator b and denominator a. If a is not specified, it defaults to 1. If n is not specified, or specified as [], it will be chosen such that the signal has a chance to die down to -120dB, or to not explode beyond 120dB, or to show five periods if there is no significant damping. If no return arguments are requested, plot the results. See also: freqz, zplane. 3.5.8 isallpass --------------- -- Function File: L = isallpass (B, A) -- Function File: L = isallpass (SOS) Determine whether a digital filter is allpass. The filter might be defined by the numerator coefficients, B, and the denominator coefficients, A, or, alternatively, by a matrix of second-order sections, SOS. Example: a = [1 2 3]; b = [3 2 1]; isallpass (b, a) Ref [1] Shyu, Jong-Jy, & Pei, Soo-Chang, A new approach to the design of complex all-pass IIR digital filters, Signal Processing, 40(2–3), 207–215, 1994. https://doi.org/10.1016/0165-1684(94)90068-x Ref [2] Vaidyanathan, P. P. Multirate Systems and Filter Banks. 1st edition, Pearson College Div, 1992. 3.5.9 ismaxphase ---------------- -- Function File: L = ismaxphase (B, A) -- Function File: L = ismaxphase (SOS) -- Function File: L = ismaxphase (..., TOL) Determine whether a digital filter is maximum phase (maximum energy-delay). The filter might be defined by the numerator coefficients, B, and the denominator coefficients, A, or, alternatively, by a matrix of second-order sections, SOS. A tolerance TOL might be given to define when two numbers are close enough to be considered equal. Example: b = [1 2 4 4 2 1]; zplane (b); ismaxphase (b) Ref [1] Oppenheim, Alan, and Ronald Schafer. Discrete-Time Signal Processing. 3rd edition, Pearson, 2009. 3.5.10 isminphase ----------------- -- Function File: L = isminphase (B, A) -- Function File: L = isminphase (SOS) -- Function File: L = isminphase (..., TOL) Determine whether a digital filter is minimum phase. The filter might be defined by the numerator coefficients, B, and the denominator coefficients, A, or, alternatively, by a matrix of second-order sections, SOS. A toleranve TOL might be given to define when two numbers are close enough to be considered equal. Example: a = [1 0.5]; b = [3 1]; isminphase (b, a) Ref [1] Oppenheim, Alan, and Ronald Schafer. Discrete-Time Signal Processing. 3rd edition, Pearson, 2009. 3.5.11 isstable --------------- -- Function File: FLAG = isstable (B, A) Returns a logical output equal to TRUE, if the filter is stable. This can be done with coeffients of the filer B and A. Alternatively by using a second order sections matrix (SOS). Inputs: • B: Numerator coefficients of the filter • A: Denominator coeffients of the filter. Can be an empty vector. Output: • FLAG: Returns a logical output, equal to TRUE if the filter is stable. Examples: b = [1 2 3 4 5 5 1 2]; a = [4 5 6 7 9 10 4 6]; flag = isstable (b, a) flag = 0 Using SOS [z, p, k] = butter (6, 0.7, 'high'); sos = zp2sos (z, p, k); flag = isstable (sos) flag = 1 3.5.12 phasez ------------- -- Function File: [PHI, W] = phasez (B, A, N) -- Function File: [PHI, W] = phasez (B, A) -- Function File: [PHI, W] = phasez (SOS, N) -- Function File: [PHI, W] = phasez (SOS) -- Function File: [PHI, W] = phasez (..., N, "whole") -- Function File: [PHI, W] = phasez (..., N, Fs) -- Function File: phasez (...) Compute the phase response of digital filter defined either by its coefficients (B and A are the numerator and denominator coefficients respectively) or by its second-order sections representation, given by the matrix SOS. The output PHI is the phase response computed in a vector the vector of frequencies W. The phase response is evaluated at N angular frequencies between 0 and pi. If A is omitted, the denominator is assumed to be 1 (this corresponds to a simple FIR filter). If N is omitted, a value of 512 is assumed. If the third/forth argument, "whole", is given, the response is evaluated at N angular frequencies between 0 and 2*pi. It is possible also to pass the value "half", which will lead to the default behaviour. Example: [b, a] = butter (2, [.15,.3]); phasez (b, a); Ref [1] Oppenheim, Alan, and Ronald Schafer. Discrete-Time Signal Processing. 3rd edition, Pearson, 2009. See also: freqz, phasedelay. 3.5.13 zplane ------------- -- Function File: zplane (Z, P) -- Function File: zplane (B, A) Plot the poles and zeros on a complex plane. If the arguments are column vectors Z and P, the complex zeros Z and poles P are displayed. If the arguments are row vectors B and A, the zeros and poles of the transfer function represented by these filter coefficients are displayed. If Z and P are matrices, the columns are distinct sets of zeros and poles and are displayed together in distinct colors. Note that due to the nature of the ‘roots’ function, poles and zeros may be displayed as occurring around a circle rather than at a single point. The transfer function is B(z) b0 + b1 z^(-1) + b2 z^(-2) + ... + bM z^(-M) H(z) = ---- = -------------------------------------------- A(z) a0 + a1 z^(-1) + a2 z^(-2) + ... + aN z^(-N) b0 (z - z1) (z - z2) ... (z - zM) = -- z^(-M+N) ------------------------------ a0 (z - p1) (z - p2) ... (z - pN) If called with only one argument, the poles P defaults to an empty vector, and the denominator coefficient vector A defaults to 1.  File: signal.info, Node: Filter Conversion, Next: IIR Filter Design, Prev: Filter Analysis, Up: Function Reference 3.6 Filter Conversion ===================== 3.6.1 residued -------------- -- Function File: [R, P, F, M] = residued (B, A) Compute the partial fraction expansion (PFE) of filter H(z) = B(z)/A(z). In the usual PFE function ‘residuez’, the IIR part (poles P and residues R) is driven _in parallel_ with the FIR part (F). In this variant, the IIR part is driven by the _output_ of the FIR part. This structure can be more accurate in signal modeling applications. INPUTS: B and A are vectors specifying the digital filter H(z) = B(z)/A(z). See ‘help filter’ for documentation of the B and A filter coefficients. RETURNED: • R = column vector containing the filter-pole residues • P = column vector containing the filter poles • F = row vector containing the FIR part, if any • M = column vector of pole multiplicities EXAMPLES: See test residued verbose to see a number of examples. For the theory of operation, see ‘http://ccrma.stanford.edu/~jos/filters/residued.html’ See also: residue, residued. 3.6.2 residuez -------------- -- Function File: [R, P, F, M] = residuez (B, A) Compute the partial fraction expansion of filter H(z) = B(z)/A(z). INPUTS: B and A are vectors specifying the digital filter H(z) = B(z)/A(z). See ‘help filter’ for documentation of the B and A filter coefficients. RETURNED: • R = column vector containing the filter-pole residues • P = column vector containing the filter poles • F = row vector containing the FIR part, if any • M = column vector of pole multiplicities EXAMPLES: See test residuez verbose to see a number of examples. For the theory of operation, see ‘http://ccrma.stanford.edu/~jos/filters/residuez.html’ See also: residue, residued. 3.6.3 sos2ss ------------ -- Function File: [A, B, C, D] = sos2ss (SOS) Convert series second-order sections to state-space. See also: sos2ss, ss2tf. 3.6.4 sos2tf ------------ -- Function File: [B, A] = sos2tf (SOS) -- Function File: [B, A] = sos2tf (SOS, G) Convert series second-order sections to transfer function. INPUTS: • SOS = matrix of series second-order sections, one per row: SOS = [B1.' A1.'; ...; BN.' AN.'] where ‘B1.' = [b0 b1 b2] and A1.' = [a0 a1 a2]’ for section 1, etc. a0 is usually equal to 1 because all 2nd order transfer functions can be scaled so that a0 = 1. However, this is not mandatory for this implementation, which supports all kinds of transfer functions, including first order transfer functions. See ‘filter’ for documentation of the second-order direct-form filter coefficients Bi and Ai. • G is an overall gain factor that effectively scales the output B vector (or any one of the input Bi vectors). If not given the gain is assumed to be 1. RETURNED: B and A are vectors specifying the analog or digital filter H(s) = B(s)/A(s) or H(z) = B(z)/A(z). See ‘filter’ for further details. See also: tf2sos, zp2sos, sos2pz, zp2tf, tf2zp. 3.6.5 sos2zp ------------ -- Function File: [Z, P, K] = sos2zp (SOS) -- Function File: [Z, P, K] = sos2zp (SOS, G) Convert series second-order sections to zeros, poles, and gains (pole residues). INPUTS: • SOS = matrix of series second-order sections, one per row: SOS = [B1.' A1.'; ...; BN.' AN.'] where ‘B1.' = [b0 b1 b2] and A1.' = [a0 a1 a2]’ for section 1, etc. a0 is usually equal to 1 because all 2nd order transfer functions can be scaled so that a0 = 1. However, this is not mandatory for this implementation, which supports all kinds of transfer functions, including first order transfer functions. See ‘filter’ for documentation of the second-order direct-form filter coefficients Bi and Ai. • G is an overall gain factor that effectively scales any one of the input Bi vectors. If not given the gain is assumed to be 1. RETURNED: • Z = column-vector containing all zeros (roots of B(z)) • P = column-vector containing all poles (roots of A(z)) • K = overall gain = B(Inf) EXAMPLE: [z, p, k] = sos2zp ([1 0 1, 1 0 -0.81; 1 0 0, 1 0 0.49]) ⇒ z = 0 + 1i 0 - 1i 0 + 0i 0 + 0i ⇒ p = -0.9000 + 0i 0.9000 + 0i 0 + 0.7000i 0 - 0.7000i ⇒ k = 1 See also: zp2sos, sos2tf, tf2sos, zp2tf, tf2zp. 3.6.6 ss2tf ----------- -- Function File: [NUM, DEN] = ss2tf (A, B, C, D) Conversion from state-space to transfer function representation. The state space system: . x = Ax + Bu y = Cx + Du is converted to a transfer function: num(s) G(s)=------- den(s) 3.6.7 ss2zp ----------- -- Function File: [Z, P, K] = ss2zp (A, B, C, D) Converts a state space representation to a set of poles and zeros; K is a gain associated with the zeros. 3.6.8 tf2sos ------------ -- Function File: [SOS, G] = tf2sos (B, A) -- Function File: SOS = tf2sos (B, A) Convert direct-form filter coefficients to series second-order sections. INPUTS: B and A are vectors specifying the digital filter H(z) = B(z)/A(z). See ‘filter’ for documentation of the B and A filter coefficients. RETURNED: • SOS = matrix of series second-order sections, one per row: SOS = [B1.' A1.'; ...; BN.' AN.'] where ‘B1.' = [b0 b1 b2] and A1.' = [1 a1 a2]’ for section 1, etc. The b0 entry must be nonzero for each section (zeros at infinity not supported). • G is an overall gain factor that effectively scales any one of the Bi vectors. If called with only one output argument, the overall filter gain is applied to the first second-order section in the matrix SOS. EXAMPLE: B = [1 0 0 0 0 1]; A = [1 0 0 0 0 .9]; [sos, g] = tf2sos (B, A) sos = 1.00000 0.61803 1.00000 1.00000 0.60515 0.95873 1.00000 -1.61803 1.00000 1.00000 -1.58430 0.95873 1.00000 1.00000 -0.00000 1.00000 0.97915 -0.00000 g = 1 See also: sos2tf, zp2sos, sos2pz, zp2tf, tf2zp. 3.6.9 tf2ss ----------- -- Function File: [A, B, C, D] = tf2ss (NUM, DEN) Conversion from transfer function to state-space. The state space system: . x = Ax + Bu y = Cx + Du is obtained from a transfer function: num(s) G(s)=------- den(s) The state space system matrices obtained from this function will be in observable companion form as Wolovich’s Observable Structure Theorem is used. 3.6.10 tf2zp ------------ -- Function File: [Z, P, K] = tf2zp (NUM, DEN) Convert transfer functions to poles-and-zero representations. Returns the zeros and poles of the system defined by NUM/DEN. K is a gain associated with the system zeros. 3.6.11 zp2sos ------------- -- Function File: [SOS, G] = zp2sos (Z) -- Function File: [SOS, G] = zp2sos (Z, P) -- Function File: [SOS, G] = zp2sos (Z, P, K) -- Function File: SOS = zp2sos (...) Convert filter poles and zeros to second-order sections. INPUTS: • Z = column-vector containing the filter zeros • P = column-vector containing the filter poles • K = overall filter gain factor. If not given the gain is assumed to be 1. RETURNED: • SOS = matrix of series second-order sections, one per row: SOS = [B1.' A1.'; ...; BN.' AN.'] where ‘B1.' = [b0 b1 b2] and A1.' = [a0 a1 a2]’ for section 1, etc. See ‘filter’ for documentation of the second-order direct-form filter coefficients Bi and %Ai, i=1:N. • G is the overall gain factor that effectively scales any one of the Bi vectors. If called with only one output argument, the overall filter gain is applied to the first second-order section in the matrix SOS. EXAMPLE: [z, p, k] = tf2zp ([1 0 0 0 0 1], [1 0 0 0 0 .9]); [sos, g] = zp2sos (z, p, k) sos = 1.0000 0.6180 1.0000 1.0000 0.6051 0.9587 1.0000 -1.6180 1.0000 1.0000 -1.5843 0.9587 1.0000 1.0000 0 1.0000 0.9791 0 g = 1 See also: sos2zp, sos2tf, tf2sos, zp2tf, tf2zp. 3.6.12 zp2ss ------------ -- Function File: [A, B, C, D] = zp2ss (Z, P, K) Conversion from zero / pole to state space. *Inputs* Z P Vectors of (possibly) complex poles and zeros of a transfer function. Complex values must come in conjugate pairs (i.e., x+jy in Z means that x-jy is also in Z). K Real scalar (leading coefficient). *Outputs* A B C D The state space system, in the form: . x = Ax + Bu y = Cx + Du 3.6.13 zp2tf ------------ -- Function File: [NUM, DEN] = zp2tf (Z, P, K) Converts zeros / poles to a transfer function. *Inputs* Z P Vectors of (possibly complex) poles and zeros of a transfer function. Complex values must appear in conjugate pairs. K Real scalar (leading coefficient).  File: signal.info, Node: IIR Filter Design, Next: FIR Filter Design, Prev: Filter Conversion, Up: Function Reference 3.7 IIR Filter Design ===================== 3.7.1 besselap -------------- -- Function File: [ZERO, POLE, GAIN] = besselap (N) Return bessel analog filter prototype. References: http://en.wikipedia.org/wiki/Bessel_polynomials 3.7.2 besself ------------- -- Function File: [B, A] = besself (N, W) -- Function File: [B, A] = besself (N, W, "high") -- Function File: [Z, P, G] = besself (...) -- Function File: [A, B, C, D] = besself (...) -- Function File: [...] = besself (..., "z") Generate a Bessel filter. Default is a Laplace space (s) filter. [b,a] = besself(n, Wc) low pass filter with cutoff pi*Wc radians [b,a] = besself(n, Wc, ’high’) high pass filter with cutoff pi*Wc radians [z,p,g] = besself(...) return filter as zero-pole-gain rather than coefficients of the numerator and denominator polynomials. [...] = besself(...,’z’) return a discrete space (Z) filter, W must be less than 1. [a,b,c,d] = besself(...) return state-space matrices References: Proakis & Manolakis (1992). Digital Signal Processing. New York: Macmillan Publishing Company. 3.7.3 bilinear -------------- -- Function File: [ZB, ZA] = bilinear (SB, SA, T) -- Function File: [ZB, ZA] = bilinear (SZ, SP, SG, T) -- Function File: [ZZ, ZP, ZG] = bilinear (...) Transform a s-plane filter specification into a z-plane specification. Filters can be specified in either zero-pole-gain or transfer function form. The input form does not have to match the output form. 1/T is the sampling frequency represented in the z plane. Note: this differs from the bilinear function in the signal processing toolbox, which uses 1/T rather than T. Theory: Given a piecewise flat filter design, you can transform it from the s-plane to the z-plane while maintaining the band edges by means of the bilinear transform. This maps the left hand side of the s-plane into the interior of the unit circle. The mapping is highly non-linear, so you must design your filter with band edges in the s-plane positioned at 2/T tan(w*T/2) so that they will be positioned at w after the bilinear transform is complete. The following table summarizes the transformation: +---------------+-----------------------+----------------------+ | Transform | Zero at x | Pole at x | | H(S) | H(S) = S-x | H(S)=1/(S-x) | +---------------+-----------------------+----------------------+ | 2 z-1 | zero: (2+xT)/(2-xT) | zero: -1 | | S -> - --- | pole: -1 | pole: (2+xT)/(2-xT) | | T z+1 | gain: (2-xT)/T | gain: (2-xT)/T | +---------------+-----------------------+----------------------+ With tedious algebra, you can derive the above formulae yourself by substituting the transform for S into H(S)=S-x for a zero at x or H(S)=1/(S-x) for a pole at x, and converting the result into the form: H(Z)=g prod(Z-Xi)/prod(Z-Xj) Please note that a pole and a zero at the same place exactly cancel. This is significant since the bilinear transform creates numerous extra poles and zeros, most of which cancel. Those which do not cancel have a "fill-in" effect, extending the shorter of the sets to have the same number of as the longer of the sets of poles and zeros (or at least split the difference in the case of the band pass filter). There may be other opportunistic cancellations but I will not check for them. Also note that any pole on the unit circle or beyond will result in an unstable filter. Because of cancellation, this will only happen if the number of poles is smaller than the number of zeros. The analytic design methods all yield more poles than zeros, so this will not be a problem. References: Proakis & Manolakis (1992). Digital Signal Processing. New York: Macmillan Publishing Company. 3.7.4 buttap ------------ -- Function File: [Z, P, G] = buttap (N) Design lowpass analog Butterworth filter. This function exists for MATLAB compatibility only, and is equivalent to ‘butter (N, 1, "s")’. See also: butter. 3.7.5 butter ------------ -- Function File: [B, A] = butter (N, WC) -- Function File: [B, A] = butter (N, WC, FILTER_TYPE) -- Function File: [Z, P, G] = butter (...) -- Function File: [A, B, C, D] = butter (...) -- Function File: [...] = butter (..., "s") Generate a Butterworth filter. Default is a discrete space (Z) filter. The cutoff frequency, WC should be specified in radians for analog filters. For digital filters, it must be a value between zero and one. For bandpass filters, WC is a two-element vector with ‘w(1) < w(2)’. The filter type must be one of "low", "high", "bandpass", or "stop". The default is "low" if WC is a scalar and "bandpass" if WC is a two-element vector. If the final input argument is "s" design an analog Laplace space filter. Low pass filter with cutoff ‘pi*Wc’ radians: [b, a] = butter (n, Wc) High pass filter with cutoff ‘pi*Wc’ radians: [b, a] = butter (n, Wc, "high") Band pass filter with edges ‘pi*Wl’ and ‘pi*Wh’ radians: [b, a] = butter (n, [Wl, Wh]) Band reject filter with edges ‘pi*Wl’ and ‘pi*Wh’ radians: [b, a] = butter (n, [Wl, Wh], "stop") Return filter as zero-pole-gain rather than coefficients of the numerator and denominator polynomials: [z, p, g] = butter (...) Return a Laplace space filter, WC can be larger than 1: [...] = butter (..., "s") Return state-space matrices: [a, b, c, d] = butter (...) References: Proakis & Manolakis (1992). Digital Signal Processing. New York: Macmillan Publishing Company. 3.7.6 buttord ------------- -- Function File: N = buttord (WP, WS, RP, RS) -- Function File: N = buttord ([WP1, WP2], [WS1, WS2], RP, RS) -- Function File: N = buttord ([WP1, WP2], [WS1, WS2], RP, RS, "s") -- Function File: [N, WC_P] = buttord (...) -- Function File: [N, WC_P, WC_S] = buttord (...) Compute the minimum filter order of a Butterworth filter with the desired response characteristics. The filter frequency band edges are specified by the passband frequency WP and stopband frequency WS. Frequencies are normalized to the Nyquist frequency in the range [0,1]. RP is the allowable passband ripple measured in decibels, and RS is the minimum attenuation in the stop band, also in decibels. The output arguments N and WC_P (or N and WC_N) can be given as inputs to ‘butter’. Using WC_P makes the filter characteristic touch at least one pass band corner and using WC_S makes the characteristic touch at least one stop band corner. If WP and WS are scalars, then WP is the passband cutoff frequency and WS is the stopband edge frequency. If WS is greater than WP, the filter is a low-pass filter. If WP is greater than WS, the filter is a high-pass filter. If WP and WS are vectors of length 2, then WP defines the passband interval and WS defines the stopband interval. If WP is contained within WS (WS1 < WP1 < WP2 < WS2), the filter is a band-pass filter. If WS is contained within WP (WP1 < WS1 < WS2 < WP2), the filter is a band-stop or band-reject filter. If the optional argument ‘"s"’ is given, the minimum order for an analog elliptic filter is computed. All frequencies WP and WS are specified in radians per second. Theory: For Low pass filters, |H(W)|^2 = 1/[1+(W/Wc)^(2N)] = 10^(-R/10). With some algebra, you can solve simultaneously for Wc and N given Ws,Rs and Wp,Rp. Rounding N to the next greater integer, one can recalculate the allowable range for Wc (filter caracteristic touching the pass band edge or the stop band edge). For other types of filter, before making the above calculation, the requirements must be transformed to LP requirements. After calculation, Wc must be transformed back to original filter type. See also: butter, cheb1ord, cheb2ord, ellipord. 3.7.7 cheb ---------- -- Function File: cheb (N, X) Returns the value of the nth-order Chebyshev polynomial calculated at the point x. The Chebyshev polynomials are defined by the equations: / cos(n acos(x), |x| <= 1 Tn(x) = | \ cosh(n acosh(x), |x| > 1 If x is a vector, the output is a vector of the same size, where each element is calculated as y(i) = Tn(x(i)). 3.7.8 cheb1ap ------------- -- Function File: [Z, P, G] = cheb1ap (N, RP) Design lowpass analog Chebyshev type I filter. This function exists for MATLAB compatibility only, and is equivalent to ‘cheby1 (N, RP, 1, "s")’. See also: cheby1. 3.7.9 cheb1ord -------------- -- Function File: N = cheb1ord (WP, WS, RP, RS) -- Function File: N = cheb1ord ([WP1, WP2], [WS1, WS2], RP, RS) -- Function File: N = cheb1ord ([WP1, WP2], [WS1, WS2], RP, RS, "s") -- Function File: [N, WC] = cheb1ord (...) -- Function File: [N, WC_P, WC_S] = cheb1ord (...) Compute the minimum filter order of a Chebyshev type I filter with the desired response characteristics. The filter frequency band edges are specified by the passband frequency WP and stopband frequency WS. Frequencies are normalized to the Nyquist frequency in the range [0,1]. RP is the allowable passband ripple measured in decibels, and RS is the minimum attenuation in the stop band, also in decibels. The output arguments N and WC_P (or N and WC_S) can be given as inputs to ‘cheby1’. Using WC_P makes the filter characteristic touch at least one pass band corner and using WC_S makes the characteristic touch at least one stop band corner. If WP and WS are scalars, then WP is the passband cutoff frequency and WS is the stopband edge frequency. If WS is greater than WP, the filter is a low-pass filter. If WP is greater than WS, the filter is a high-pass filter. If WP and WS are vectors of length 2, then WP defines the passband interval and WS defines the stopband interval. If WP is contained within WS (WS1 < WP1 < WP2 < WS2), the filter is a band-pass filter. If WS is contained within WP (WP1 < WS1 < WS2 < WP2), the filter is a band-stop or band-reject filter. If the optional argument ‘"s"’ is given, the minimum order for an analog elliptic filter is computed. All frequencies WP and WS are specified in radians per second. See also: buttord, cheby1, cheb2ord, ellipord. 3.7.10 cheb2ap -------------- -- Function File: [Z, P, G] = cheb2ap (N, RS) Design lowpass analog Chebyshev type II filter. This function exists for MATLAB compatibility only, and is equivalent to ‘cheby2 (N, RS, 1, "s")’. Demo demo cheb2ap See also: cheby2. 3.7.11 cheb2ord --------------- -- Function File: N = cheb2ord (WP, WS, RP, RS) -- Function File: N = cheb2ord ([WP1, WP2], [WS1, WS2], RP, RS) -- Function File: N = cheb2ord ([WP1, WP2], [WS1, WS2], RP, RS, "s") -- Function File: [N, WC_S] = cheb2ord (...) -- Function File: [N, WC_S, WC_P] = cheb2ord (...) Compute the minimum filter order of a Chebyshev type II filter with the desired response characteristics. The filter frequency band edges are specified by the passband frequency WP and stopband frequency WS. Frequencies are normalized to the Nyquist frequency in the range [0,1]. RP is the allowable passband ripple measured in decibels, and RS is the minimum attenuation in the stop band, also in decibels. The output arguments N and WC_P (or N and WC_S) can be given as inputs to ‘cheby2’. Using WC_P makes the filter characteristic touch at least one pass band corner and using WC_S makes the characteristic touch at least one stop band corner. If WP and WS are scalars, then WP is the passband cutoff frequency and WS is the stopband edge frequency. If WS is greater than WP, the filter is a low-pass filter. If WP is greater than WS, the filter is a high-pass filter. If WP and WS are vectors of length 2, then WP defines the passband interval and WS defines the stopband interval. If WP is contained within WS (WS1 < WP1 < WP2 < WS2), the filter is a band-pass filter. If WS is contained within WP (WP1 < WS1 < WS2 < WP2), the filter is a band-stop or band-reject filter. If the optional argument ‘"s"’ is given, the minimum order for an analog elliptic filter is computed. All frequencies WP and WS are specified in radians per second. See also: buttord, cheb1ord, cheby2, ellipord. 3.7.12 cheby1 ------------- -- Function File: [B, A] = cheby1 (N, RP, W) -- Function File: [B, A] = cheby1 (N, RP, W, "high") -- Function File: [B, A] = cheby1 (N, RP, [WL, WH]) -- Function File: [B, A] = cheby1 (N, RP, [WL, WH], "stop") -- Function File: [Z, P, G] = cheby1 (...) -- Function File: [A, B, C, D] = cheby1 (...) -- Function File: [...] = cheby1 (..., "s") Generate a Chebyshev type I filter with RP dB of passband ripple. [b, a] = cheby1(n, Rp, Wc) low pass filter with cutoff pi*Wc radians [b, a] = cheby1(n, Rp, Wc, ’high’) high pass filter with cutoff pi*Wc radians [b, a] = cheby1(n, Rp, [Wl, Wh]) band pass filter with edges pi*Wl and pi*Wh radians [b, a] = cheby1(n, Rp, [Wl, Wh], ’stop’) band reject filter with edges pi*Wl and pi*Wh radians [z, p, g] = cheby1(...) return filter as zero-pole-gain rather than coefficients of the numerator and denominator polynomials. [...] = cheby1(...,’s’) return a Laplace space filter, W can be larger than 1. [a,b,c,d] = cheby1(...) return state-space matrices References: Parks & Burrus (1987). Digital Filter Design. New York: John Wiley & Sons, Inc. 3.7.13 cheby2 ------------- -- Function File: [B, A] = cheby2 (N, RS, WC) -- Function File: [B, A] = cheby2 (N, RS, WC, "high") -- Function File: [B, A] = cheby2 (N, RS, [WL, WH]) -- Function File: [B, A] = cheby2 (N, RS, [WL, WH], "stop") -- Function File: [Z, P, G] = cheby2 (...) -- Function File: [A, B, C, D] = cheby2 (...) -- Function File: [...] = cheby2 (..., "s") Generate a Chebyshev type II filter with RS dB of stopband attenuation. [b, a] = cheby2(n, Rs, Wc) low pass filter with cutoff pi*Wc radians [b, a] = cheby2(n, Rs, Wc, ’high’) high pass filter with cutoff pi*Wc radians [b, a] = cheby2(n, Rs, [Wl, Wh]) band pass filter with edges pi*Wl and pi*Wh radians [b, a] = cheby2(n, Rs, [Wl, Wh], ’stop’) band reject filter with edges pi*Wl and pi*Wh radians [z, p, g] = cheby2(...) return filter as zero-pole-gain rather than coefficients of the numerator and denominator polynomials. [...] = cheby2(...,’s’) return a Laplace space filter, W can be larger than 1. [a,b,c,d] = cheby2(...) return state-space matrices References: Parks & Burrus (1987). Digital Filter Design. New York: John Wiley & Sons, Inc. 3.7.14 ellip ------------ -- Function File: [B, A] = ellip (N, RP, RS, WP) -- Function File: [B, A] = ellip (N, RP, RS, WP, "high") -- Function File: [B, A] = ellip (N, RP, RS, [WL, WH]) -- Function File: [B, A] = ellip (N, RP, RS, [WL, WH], "stop") -- Function File: [Z, P, G] = ellip (...) -- Function File: [A, B, C, D] = ellip (...) -- Function File: [...] = ellip (..., "s") Generate an elliptic or Cauer filter with RP dB of passband ripple and RS dB of stopband attenuation. [b,a] = ellip(n, Rp, Rs, Wp) low pass filter with order n, cutoff pi*Wp radians, Rp decibels of ripple in the passband and a stopband Rs decibels down. [b,a] = ellip(n, Rp, Rs, Wp, ’high’) high pass filter with cutoff pi*Wp... [b,a] = ellip(n, Rp, Rs, [Wl, Wh]) band pass filter with band pass edges pi*Wl and pi*Wh ... [b,a] = ellip(n, Rp, Rs, [Wl, Wh], ’stop’) band reject filter with edges pi*Wl and pi*Wh, ... [z,p,g] = ellip(...) return filter as zero-pole-gain. [...] = ellip(...,’s’) return a Laplace space filter, W can be larger than 1. [a,b,c,d] = ellip(...) return state-space matrices References: - Oppenheim, Alan V., Discrete Time Signal Processing, Hardcover, 1999. - Parente Ribeiro, E., Notas de aula da disciplina TE498 - Processamento Digital de Sinais, UFPR, 2001/2002. 3.7.15 ellipap -------------- -- Function File: [Z, P, G] = ellipap (N, RP, RS) Design lowpass analog elliptic filter. This function exists for MATLAB compatibility only, and is equivalent to ‘ellip (N, RP, RS, 1, "s")’. See also: ellip. 3.7.16 ellipord --------------- -- Function File: N = ellipord (WP, WS, RP, RS) -- Function File: N = ellipord ([WP1, WP2], [WS1, WS2], RP, RS) -- Function File: N = ellipord ([WP1, WP2], [WS1, WS2], RP, RS, "s") -- Function File: [N, WC] = ellipord (...) Compute the minimum filter order of an elliptic filter with the desired response characteristics. The filter frequency band edges are specified by the passband frequency WP and stopband frequency WS. Frequencies are normalized to the Nyquist frequency in the range [0,1]. RP is the allowable passband ripple measured in decibels, and RS is the minimum attenuation in the stop band, also in decibels. The output arguments N and WC can be given as inputs to ‘ellip’. If WP and WS are scalars, then WP is the passband cutoff frequency and WS is the stopband edge frequency. If WS is greater than WP, the filter is a low-pass filter. If WP is greater than WS, the filter is a high-pass filter. If WP and WS are vectors of length 2, then WP defines the passband interval and WS defines the stopband interval. If WP is contained within WS (WS1 < WP1 < WP2 < WS2), the filter is a band-pass filter. If WS is contained within WP (WP1 < WS1 < WS2 < WP2), the filter is a band-stop or band-reject filter. If the optional argument ‘"s"’ is given, the minimum order for an analog elliptic filter is computed. All frequencies WP and WS are specified in radians per second. Reference: Lamar, Marcus Vinicius, ‘Notas de aula da disciplina TE 456 - Circuitos Analogicos II’, UFPR, 2001/2002. See also: buttord, cheb1ord, cheb2ord, ellip. 3.7.17 firpm ------------ -- Loadable Function: B = firpm (N, F, A) -- Loadable Function: B = firpm (N, F, @RESPFN) -- Loadable Function: B = firpm (N, F, {@RESPFN, ...}) -- Loadable Function: B = firpm (..., W) -- Loadable Function: B = firpm (..., CLASS) -- Loadable Function: B = firpm (..., {ACCURACY, ...}) -- Loadable Function: [B, MINIMAX] = firpm (...) -- Loadable Function: [B, MINIMAX, RES] = firpm (...) Designs a linear-phase FIR filter according to given specifications and the ‘minimax’ criterion. The method (per McClellan et al.(1)) uses successive approximation to minimize the maximum weighted error between the desired and actual frequency response of the filter. Such filters are variably described as being ‘minimax’, ‘equiripple’, or ‘optimal (in the Chebyshev sense)’. Arguments ========= ... Where shown as the first argument to ‘firpm’, indicates that any previously-indicated list of arguments may substitute for the ellipsis. N A positive integer giving the filter order. F A vector of real-numbers, increasing in the range [0,1], giving the frequencies of the left and right edges of each band for which a specific amplitude response is desired: [l1 r1 l2 r2 ...]. 1 represents the Nyquist-frequency. Transition-bands are defined implicitly as the regions between or outside the given bands. A A vector of real-numbers giving the desired amplitude response. An amplitude value is given either for each band edge: [a(l1) a(r1) a(l2) a(r2) ...], or for each band: [a1 a2 ...]. In the former case, in-band amplitude is determined by linear interpolation between the given band-edge values. 1 represents unity-gain, 0 represents infinite attenuation, and −1 represents a phase change of pi radians. Note that amplitude response is necessarily zero at F=0 for type III and IV filters, and at F=1 for type II and III filters. @RESPFN A handle to a ‘response function’ that supplies the desired amplitude response and error-weighting. This, unlike A above, allows the response to be arbitrary (subject to the note above). firpm invokes the response function according to the following syntax: AG = respFn (N,F,G,W, ...) [AG WG] = respFn (N,F,G,W, ...) SYMMETRY = respFn ("defaults", {N,F,G,W, ...}) where: • N and F are as given to firpm. • W is as given to firpm, or ones if not given. • AG and WG are the desired amplitude and weighting functions evaluated at each frequency in vector G (which are frequencies within the non-transition bands of F). Returning AG alone gives uniform weighting. • SYMMETRY is either "even" or "odd"; this provides an alternative to using the CLASS values "symmetric" and "antisymmetric". • Per the ellipses shown here and above, when @RESPFN is given contained in a cell-array, any additionally contained values are appended to the RESPFN invocation argument-list. W When used in conjunction with A, W is a vector of positive real-numbers giving error-weightings to be applied at each given band-edge [w(l1) w(r1) w(l2) w(r2) ...], or for each band [w1 w2 ...]. In the former case, in-band weighting is determined by linear interpolation between the given band-edge values. A higher relative error weighting yields a lower relative error. When used in conjunction with @RESPFN, W is a vector (constrained as above) that is passed through to RESPFN. CLASS A string, which may be abbreviated, giving the filter-class: • "symmetric" (the default) for type I or II filters, • "antisymmetric" (or "hilbert") for standard type III or IV filters, • "differentiator" for type III or IV filters with inverted phase and with error-weighting (further to W) of 2/f applied in the pass-band(s). ACCURACY, ... Up to three properties contained within a cell-array: ACCURACY, PERSISTENCE, ROBUSTNESS, that respectively control how close the computed filter will be to the ideal minimax solution, the number of computation iterations over which the required accuracy will be sought, and the precision of certain internal processing. Each can each be set to a small positive number (typically ≤3), to increase the relevant item; this may increase computation time, but the need to do so should be rare. A value of 0 can be used to leave an item unchanged. Alternatively, setting ACCURACY ≥16 emulates MATLAB’s LGRID argument. Results ======= If a problem occurs during the computation, a diagnostic message will normally be displayed. If this happens, adjusting ACCURACY, PERSISTENCE, or ROBUSTNESS may provide the solution. Some filters however, may not be realizable due to machine-precision limitations. If a filter can be computed, returned values are as follows: B A length N+1 row-vector containing the computed filter coefficients. MINIMAX The absolute value of the minimized, maximum weighted error, or this number negated if the required accuracy could not be achieved. RES A structure of data relating to the filter computation and a partial response-analysis of the resultant filter; fields are vectors: ‘fgrid’ Analysis frequencies per F. ‘des’ Desired amplitude response. ‘wt’ Error weighting. ‘H’ Complex frequency response. ‘error’ Desired minus actual amplitude response. ‘iextr’ Indices of local peaks in ‘error’. ‘fextr’ Frequencies of local peaks in ‘error’. Using RES is not recommended because it can be slow to compute and, since the analysis excludes transition-bands, any ‘anomalies’(2) therein are not easy to discern. In general, ‘freqz’ suffices to check that the response of the computed filter is satisfactory. Examples ======== # Low-pass with frequencies in Hz: Fs = 96000; Fn = Fs/2; # Sampling & Nyquist frequencies. b = firpm (50, [0 20000 28000 48000] / Fn, [1 0]); # Type IV high-pass: b = firpm (31, [0 0.5 0.7 1], [0 1], "antisym"); # Inverse-sinc (arbitrary response): b = firpm (20, [0 0.5 0.9 1], @(n,f,g) ... deal ((g<=f(2))./sinc (g), (g>=f(3))*9+1)); # Band-pass with filter-response check: freqz (firpm (40, [0 3 4 6 8 10]/10, [0 1 0])) Further examples can be found in the ‘firpm’ and ‘firpmord’ demonstration scripts. Compatibility ============= Given invalid filter specifications, Octave emits an error and does not produce a filter; MATLAB in such circumstances may still produce filter coefficients. Unlike with MATLAB, with Octave MINIMAX can be negative; for compatibility, take the absolute value. See also: firpmord. 3.7.18 firpmord --------------- -- Function File: [N, FOUT, A, W] = firpmord (F, A, D) -- Function File: [N, FOUT, A, W] = firpmord (F, A, D, FS) -- Function File: C = firpmord (F, A, D, "cell") -- Function File: C = firpmord (F, A, D, FS, "cell") Estimate the filter-order needed for ‘firpm’ to design a type-I or type-II linear-phase FIR filter according to the given specifications. Arguments ========= F A vector of real-numbers, increasing in the range (0, FS/2), giving the frequencies of the left and right edges of each band for which a specific amplitude response is desired (omitting 0 and FS/2, which are implied): [r1 l2 r2 ...]. Transition-bands are defined implicitly as the regions between the given bands. A A vector of real-numbers giving the ideal amplitude response. An amplitude value is given for each band specified by F: [a1 a2 ...]. 1 represents unity-gain, 0 represents infinite attenuation, and −1 represents a phase change of pi radians. D A vector of positive real-numbers giving the maximum allowable linear deviation from the amplitudes given in A, thus constraining the actual amplitude response (where defined by F) to be within A +/− D. Note that, though related, D does not equate to ‘firpm’’s W argument. FS The sampling-frequency, which defaults to 2. Usage ===== The function returns the estimated filter-order, together with the other design specification values, in one of two forms suitable for use with ‘firpm’. By default, multiple return values are used; alternatively, by giving "cell" (or "c") as the last argument to ‘firpmord’, the returned values are contained within a cell-array that can, if desired, be passed directly to ‘firpm’. The following examples illustrate the use of both mechanisms, as well as aspects of ‘firpmord’ usage in general: # Low-pass; frequencies in kHz: [n f a w] = firpmord ([2.5 3], [1 0], [0.01 db2mag(-60)], 8); b = firpm (n, f, a, w); # Band-pass: c = firpmord ([3 4 8 9], [0 1 0], [1e-3 1e-2 1e-3], 20, "cell"); b = firpm (c{:}); # High-pass: b = firpm (firpmord ([6.4 8]/16, [0 1], [1e-4 0.01], "c"){:}); In cases where elements of D follow a repeating pattern (e.g. all the elements are equal, or elements corresponding to pass-bands are equal and elements corresponding to stop-bands are equal), only as many elements as are needed to establish the pattern need be given. For example, the following ‘firpmord’ invocation pairs are equivalent: # Low-pass: firpmord ([0.4 0.5], [0 1], [db2mag(-72) db2mag(-72)]); firpmord ([0.4 0.5], [0 1], [db2mag(-72)]); # Multi-band-pass: ds = db2mag(-80); dp = 0.01; firpmord ([1 2 3 4 5 6 7 8]/10, [0 1 0 1 0], [ds dp ds dp ds]); firpmord ([1 2 3 4 5 6 7 8]/10, [0 1 0 1 0], [ds dp]); Notes ===== The estimation algorithm used is per Ichige et al.(3) Accuracy tends to decrease as the number of bands increases. Even with two bands (i.e. high-pass or low-pass), the algorithm may under- or over-estimate. See the ‘firpmord’ demonstrations for some examples. In order to precisely determine the minimum order needed for a particular design, ‘firpmord’ could be used to seed an algorithm iterating invocations of ‘firpm’ (as exemplified in demonstration number five). Related documentation ===================== See also: firpm, kaiserord. 3.7.19 impinvar --------------- -- Function File: [B_OUT, A_OUT] = impinvar (B, A, FS, TOL) -- Function File: [B_OUT, A_OUT] = impinvar (B, A, FS) -- Function File: [B_OUT, A_OUT] = impinvar (B, A) Converts analog filter with coefficients B and A to digital, conserving impulse response. If FS is not specified, or is an empty vector, it defaults to 1Hz. If TOL is not specified, it defaults to 0.0001 (0.1%) This function does the inverse of impinvar so that the following example should restore the original values of A and B. ‘invimpinvar’ implements the reverse of this function. [b, a] = impinvar (b, a); [b, a] = invimpinvar (b, a); Reference: Thomas J. Cavicchi (1996) “Impulse invariance and multiple-order polesâ€. IEEE transactions on signal processing, Vol 44 (9): 2344–2347 See also: bilinear, invimpinvar. 3.7.20 invimpinvar ------------------ -- Function File: [B_OUT, A_OUT] = invimpinvar (B, A, FS, TOL) -- Function File: [B_OUT, A_OUT] = invimpinvar (B, A, FS) -- Function File: [B_OUT, A_OUT] = invimpinvar (B, A) Converts digital filter with coefficients B and A to analog, conserving impulse response. This function does the inverse of impinvar so that the following example should restore the original values of A and B. [b, a] = impinvar (b, a); [b, a] = invimpinvar (b, a); If FS is not specified, or is an empty vector, it defaults to 1Hz. If TOL is not specified, it defaults to 0.0001 (0.1%) Reference: Thomas J. Cavicchi (1996) “Impulse invariance and multiple-order polesâ€. IEEE transactions on signal processing, Vol 40 (9): 2344–2347 See also: bilinear, impinvar. 3.7.21 ncauer ------------- -- Function File: [Z, P, G] = cauer(RP, RS, N) Analog prototype for Cauer filter. Rp Passband ripple Rs Stopband ripple n Desired order z complex vector of zeros for the model. p complex vector of poles for the model. g gain value. References: - Serra, Celso Penteado, Teoria e Projeto de Filtros, Campinas: CARTGRAF, 1983. - Lamar, Marcus Vinicius, Notas de aula da disciplina TE 456 - Circuitos Analogicos II, UFPR, 2001/2002. 3.7.22 pei_tseng_notch ---------------------- -- Function File: [B, A] = pei_tseng_notch (FREQUENCIES, BANDWIDTHS) Return coefficients for an IIR notch-filter with one or more filter frequencies and according (very narrow) bandwidths to be used with ‘filter’ or ‘filtfilt’. The filter construction is based on an allpass which performs a reversal of phase at the filter frequencies. Thus, the mean of the phase-distorted and the original signal has the respective frequencies removed. See the demo for an illustration. Original source: Pei, Soo-Chang, and Chien-Cheng Tseng "IIR Multiple Notch Filter Design Based on Allpass Filter" 1996 IEEE Tencon doi: 10.1109/TENCON.1996.608814) 3.7.23 sftrans -------------- -- Function File: [SZ, SP, SG] = sftrans (SZ, SP, SG, W, STOP) Transform band edges of a generic lowpass filter (cutoff at W=1) represented in splane zero-pole-gain form. W is the edge of the target filter (or edges if band pass or band stop). Stop is true for high pass and band stop filters or false for low pass and band pass filters. Filter edges are specified in radians, from 0 to pi (the nyquist frequency). Theory: Given a low pass filter represented by poles and zeros in the splane, you can convert it to a low pass, high pass, band pass or band stop by transforming each of the poles and zeros individually. The following table summarizes the transformation: Transform Zero at x Pole at x ---------------- ------------------------- ------------------------ Low Pass zero: Fc x/C pole: Fc x/C S -> C S/Fc gain: C/Fc gain: Fc/C ---------------- ------------------------- ------------------------ High Pass zero: Fc C/x pole: Fc C/x S -> C Fc/S pole: 0 zero: 0 gain: -x gain: -1/x ---------------- ------------------------- ------------------------ Band Pass zero: b +- sqrt(b^2-FhFl) pole: b +- sqrt(b^2-FhFl) S^2+FhFl pole: 0 zero: 0 S -> C -------- gain: C/(Fh-Fl) gain: (Fh-Fl)/C S(Fh-Fl) b=x/C (Fh-Fl)/2 b=x/C (Fh-Fl)/2 ---------------- ------------------------- ------------------------ Band Stop zero: b +- sqrt(b^2-FhFl) pole: b +- sqrt(b^2-FhFl) S(Fh-Fl) pole: +-sqrt(-FhFl) zero: +-sqrt(-FhFl) S -> C -------- gain: -x gain: -1/x S^2+FhFl b=C/x (Fh-Fl)/2 b=C/x (Fh-Fl)/2 ---------------- ------------------------- ------------------------ Bilinear zero: (2+xT)/(2-xT) pole: (2+xT)/(2-xT) 2 z-1 pole: -1 zero: -1 S -> - --- gain: (2-xT)/T gain: (2-xT)/T T z+1 ---------------- ------------------------- ------------------------ where C is the cutoff frequency of the initial lowpass filter, Fc is the edge of the target low/high pass filter and [Fl,Fh] are the edges of the target band pass/stop filter. With abundant tedious algebra, you can derive the above formulae yourself by substituting the transform for S into H(S)=S-x for a zero at x or H(S)=1/(S-x) for a pole at x, and converting the result into the form: H(S)=g prod(S-Xi)/prod(S-Xj) The transforms are from the references. The actual pole-zero-gain changes I derived myself. Please note that a pole and a zero at the same place exactly cancel. This is significant for High Pass, Band Pass and Band Stop filters which create numerous extra poles and zeros, most of which cancel. Those which do not cancel have a "fill-in" effect, extending the shorter of the sets to have the same number of as the longer of the sets of poles and zeros (or at least split the difference in the case of the band pass filter). There may be other opportunistic cancellations but I will not check for them. Also note that any pole on the unit circle or beyond will result in an unstable filter. Because of cancellation, this will only happen if the number of poles is smaller than the number of zeros and the filter is high pass or band pass. The analytic design methods all yield more poles than zeros, so this will not be a problem. References: Proakis & Manolakis (1992). Digital Signal Processing. New York: Macmillan Publishing Company. ---------- Footnotes ---------- (1) J. H. McClellan, T. W. Parks and L. R. Rabiner, ‘A Computer Program for Designing Optimum FIR Linear Phase Digital Filters’, IEEE Trans. Audio Electroacoust., vol. AU-21, 1973, pp. 506–525. (2) Tapio Saramäki, ‘Finite impulse response filter design’, Chapter 4 in ‘Handbook for Digital Signal Processing’, edited by S. K. Mitra and J. F. Kaiser, John Wiley and Sons, New York, 1993, pp. 155–277. () (3) K. Ichige, M. Iwaki, algorithm and R. Ishii, ‘Accurate Estimation of Minimum Filter Length for Optimum FIR Digital Filters’, IEEE Transactions on Circuits and Systems, Vol. 47, No. 10, 2000, pp. 1008–1017  File: signal.info, Node: FIR Filter Design, Next: Transforms, Prev: IIR Filter Design, Up: Function Reference 3.8 FIR Filter Design ===================== 3.8.1 cl2bp ----------- -- Loadable Function: H = cl2bp (M, W1, W2, UP, LO) -- Loadable Function: H = cl2bp (M, W1, W2, UP, LO, GRIDSIZE) Constrained L2 bandpass FIR filter design. This is a fast implementation of the algorithm cited below. Compared to “remezâ€, it offers implicit specification of transition bands, a higher likelihood of convergence, and an error criterion combining features of both L2 and Chebyshev approaches. Inputs: M degree of cosine polynomial, i.e. the number of output coefficients will be M*2+1 W1 W2 bandpass filter cutoffs in the range 0 <= W1 < W2 <= pi, where pi is the Nyquist frequency UP vector of 3 upper bounds for [stopband1, passband, stopband2] LO vector of 3 lower bounds for [stopband1, passband, stopband2] GRIDSIZE search grid size; larger values may improve accuracy, but greatly increase calculation time. Output: A vector of M*2+1 FIR coefficients, or an empty value if the solver failed to converge. Example: h = cl2bp(30, 0.3*pi, 0.6*pi, [0.02, 1.02, 0.02], [-0.02, 0.98, -0.02], 2^11); Original Paper: I. W. Selesnick, M. Lang, and C. S. Burrus. A modified algorithm for constrained least square design of multiband FIR filters without specified transition bands. IEEE Trans. on Signal Processing, 46(2):497-501, February 1998. See also: remez. 3.8.2 fir1 ---------- -- Function File: B = fir1 (N, W) -- Function File: B = fir1 (N, W, TYPE) -- Function File: B = fir1 (N, W, TYPE, WINDOW) -- Function File: B = fir1 (N, W, TYPE, WINDOW, NOSCALE) Produce an order N FIR filter with the given frequency cutoff W, returning the N+1 filter coefficients in B. If W is a scalar, it specifies the frequency cutoff for a lowpass or highpass filter. If W is a two-element vector, the two values specify the edges of a bandpass or bandstop filter. If W is an N-element vector, each value specifies a band edge of a multiband pass/stop filter. The filter TYPE can be specified with one of the following strings: "low", "high", "stop", "pass", "bandpass", "DC-0", or "DC-1". The default is "low" is W is a scalar, "pass" if W is a pair, or "DC-0" if W is a vector with more than 2 elements. An optional shaping WINDOW can be given as a vector with length N+1. If not specified, a Hamming window of length N+1 is used. With the option "noscale", the filter coefficients are not normalized. The default is to normalize the filter such that the magnitude response of the center of the first passband is 1. To apply the filter, use the return vector B with the ‘filter’ function, for example ‘y = filter (b, 1, x)’. Examples: freqz (fir1 (40, 0.3)); freqz (fir1 (15, [0.2, 0.5], "stop")); # note the zero-crossing at 0.1 freqz (fir1 (15, [0.2, 0.5], "stop", "noscale")); See also: filter, fir2. 3.8.3 fir2 ---------- -- Function File: B = fir2 (N, F, M) -- Function File: B = fir2 (N, F, M, GRID_N) -- Function File: B = fir2 (N, F, M, GRID_N, RAMP_N) -- Function File: B = fir2 (N, F, M, GRID_N, RAMP_N, WINDOW) Produce an order N FIR filter with arbitrary frequency response M over frequency bands F, returning the N+1 filter coefficients in B. The vector F specifies the frequency band edges of the filter response and M specifies the magnitude response at each frequency. The vector F must be nondecreasing over the range [0,1], and the first and last elements must be 0 and 1, respectively. A discontinuous jump in the frequency response can be specified by duplicating a band edge in F with different values in M. The resolution over which the frequency response is evaluated can be controlled with the GRID_N argument. The default is 512 or the next larger power of 2 greater than the filter length. The band transition width for discontinuities can be controlled with the RAMP_N argument. The default is GRID_N/25. Larger values will result in wider band transitions but better stopband rejection. An optional shaping WINDOW can be given as a vector with length N+1. If not specified, a Hamming window of length N+1 is used. To apply the filter, use the return vector B with the ‘filter’ function, for example ‘y = filter (b, 1, x)’. Example: f = [0, 0.3, 0.3, 0.6, 0.6, 1]; m = [0, 0, 1, 1/2, 0, 0]; [h, w] = freqz (fir2 (100, f, m)); plot (f, m, ";target response;", w/pi, abs (h), ";filter response;"); See also: filter, fir1. 3.8.4 firls ----------- -- Function File: B = firls (N, F, A) -- Function File: B = firls (N, F, A, W) FIR filter design using least squares method. Returns a length N+1 linear phase filter such that the integral of the weighted mean squared error in the specified bands is minimized. The vector F specifies the frequencies of the band edges, normalized so that half the sample frequency is equal to 1. Each band is specified by two frequencies, to the vector must have an even length. The vector A specifies the amplitude of the desired response at each band edge. The optional argument W is a weighting function that contains one value for each band that weights the mean squared error in that band. A must be the same length as F, and W must be half the length of F. N must be even. If given an odd value, ‘firls’ increments it by 1. The least squares optimization algorithm for computing FIR filter coefficients is derived in detail in: I. Selesnick, "Linear-Phase FIR Filter Design by Least Squares," http://cnx.org/content/m10577 3.8.5 kaiserord --------------- -- Function File: [N, WN, BETA, FTYPE] = kaiserord (F, M, DEV) -- Function File: [...] = kaiserord (F, M, DEV, FS) Return the parameters needed to produce a filter of the desired specification from a Kaiser window. The vector F contains pairs of frequency band edges in the range [0,1]. The vector M specifies the magnitude response for each band. The values of M must be zero for all stop bands and must have the same magnitude for all pass bands. The deviation of the filter DEV can be specified as a scalar or a vector of the same length as M. The optional sampling rate FS can be used to indicate that F is in Hz in the range [0,FS/2]. The returned value N is the required order of the filter (the length of the filter minus 1). The vector WN contains the band edges of the filter suitable for passing to ‘fir1’. The value BETA is the parameter of the Kaiser window of length N+1 to shape the filter. The string FTYPE contains the type of filter to specify to ‘fir1’. The Kaiser window parameters n and beta are computed from the relation between ripple (A=-20*log10(dev)) and transition width (dw in radians) discovered empirically by Kaiser: / 0.1102(A-8.7) A > 50 beta = | 0.5842(A-21)^0.4 + 0.07886(A-21) 21 <= A <= 50 \ 0.0 A < 21 n = (A-8)/(2.285 dw) Example: [n, w, beta, ftype] = kaiserord ([1000, 1200], [1, 0], [0.05, 0.05], 11025); b = fir1 (n, w, kaiser (n+1, beta), ftype, "noscale"); freqz (b, 1, [], 11025); See also: fir1, kaiser. 3.8.6 qp_kaiser --------------- -- Function File: qp_kaiser (NB, AT) -- Function File: qp_kaiser (NB, AT, LINEAR) Computes a finite impulse response (FIR) filter for use with a quasi-perfect reconstruction polyphase-network filter bank. This version utilizes a Kaiser window to shape the frequency response of the designed filter. Tha number nb of bands and the desired attenuation at in the stop-band are given as parameters. The Kaiser window is multiplied by the ideal impulse response h(n)=a.sinc(a.n) and converted to its minimum-phase version by means of a Hilbert transform. By using a third non-null argument, the minimum-phase calculation is omitted at all. 3.8.7 remez ----------- -- Loadable Function: B = remez (N, F, A) -- Loadable Function: B = remez (N, F, A, W) -- Loadable Function: B = remez (N, F, A, W, FTYPE) -- Loadable Function: B = remez (N, F, A, W, FTYPE, GRIDDENSITY) Parks-McClellan optimal FIR filter design. N gives the filter order, where the generated filter length taps is n+1 F gives frequency at the band edges [b1 e1 b2 e2 b3 e3 ...] A gives amplitude at the band edges [a(b1) a(e1) a(b2) a(e2) ...] W gives weighting applied to each band FTYPE is "bandpass", "hilbert" or "differentiator" GRIDDENSITY determines how accurately the filter will be constructed. The minimum value is 16, but higher numbers are slower to compute. Frequency is in the range (0, 1), with 1 being the Nyquist frequency. 3.8.8 sgolay ------------ -- Function File: F = sgolay (P, N) -- Function File: F = sgolay (P, N, M) -- Function File: F = sgolay (P, N, M, TS) Computes the filter coefficients for all Savitzsky-Golay smoothing filters of order p for length n (odd). m can be used in order to get directly the mth derivative. In this case, ts is a scaling factor. The early rows of F smooth based on future values and later rows smooth based on past values, with the middle row using half future and half past. In particular, you can use row i to estimate x(k) based on the i-1 preceding values and the n-i following values of x values as y(k) = F(i,:) * x(k-i+1:k+n-i). Normally, you would apply the first (n-1)/2 rows to the first k points of the vector, the last k rows to the last k points of the vector and middle row to the remainder, but for example if you were running on a realtime system where you wanted to smooth based on the all the data collected up to the current time, with a lag of five samples, you could apply just the filter on row n-5 to your window of length n each time you added a new sample. Reference: Numerical recipes in C. p 650 See also: sgolayfilt.  File: signal.info, Node: Transforms, Next: Power Spectrum Analysis, Prev: FIR Filter Design, Up: Function Reference 3.9 Transforms ============== 3.9.1 bitrevorder ----------------- -- Function File: Y = bitrevorder (X) -- Function File: [Y I] = bitrevorder (X) Reorder the elements of the vector X in bit-reversed order. Equivalent to calling ‘digitrevorder (X, 2)’. See also: digitrevorder, fft, ifft. 3.9.2 cceps ----------- -- Function File: cceps (X) -- Function File: cceps (X, CORRECT) Return the complex cepstrum of the vector X. If the optional argument CORRECT has the value 1, a correction method is applied. The default is not to do this. 3.9.3 cplxreal -------------- -- Function File: [ZC, ZR] = cplxreal (Z) -- Function File: [ZC, ZR] = cplxreal (Z, TOL) -- Function File: [ZC, ZR] = cplxreal (Z, TOL, DIM) Sort the numbers Z into complex-conjugate-valued and real-valued elements. The positive imaginary complex numbers of each complex conjugate pair are returned in ZC and the real numbers are returned in ZR. TOL is a weighting factor in the range [0, 1) which determines the tolerance of the matching. The default value is ‘100 * eps’ and the resulting tolerance for a given complex pair is ‘TOL * abs (Z(i)))’. By default the complex pairs are sorted along the first non-singleton dimension of Z. If DIM is specified, then the complex pairs are sorted along this dimension. Signal an error if some complex numbers could not be paired. Signal an error if all complex numbers are not exact conjugates (to within TOL). Note that there is no defined order for pairs with identical real parts but differing imaginary parts. See also: cplxpair. 3.9.4 czt --------- -- Function File: czt (X) -- Function File: czt (X, M) -- Function File: czt (X, M, W) -- Function File: czt (X, M, W, A) Chirp z-transform. Compute the frequency response starting at a and stepping by w for m steps. a is a point in the complex plane, and w is the ratio between points in each step (i.e., radius increases exponentially, and angle increases linearly). To evaluate the frequency response for the range f1 to f2 in a signal with sampling frequency Fs, use the following: m = 32; ## number of points desired w = exp(-j*2*pi*(f2-f1)/((m-1)*Fs)); ## freq. step of f2-f1/m a = exp(j*2*pi*f1/Fs); ## starting at frequency f1 y = czt(x, m, w, a); If you don’t specify them, then the parameters default to a Fourier transform: m=length(x), w=exp(-j*2*pi/m), a=1 If x is a matrix, the transform will be performed column-by-column. 3.9.5 dct --------- -- Function File: dct (X) -- Function File: dct (X, N) Compute the discrete cosine transform of X. If N is given, then X is padded or trimmed to length N before computing the transform. If X is a matrix, compute the transform along the columns of the the matrix. The transform is faster if X is real-valued and has even length. The discrete cosine transform X can be defined as follows: N-1 X[k] = w(k) sum x[n] cos (pi (2n+1) k / 2N ), k = 0, ..., N-1 n=0 with w(0) = sqrt(1/N) and w(k) = sqrt(2/N), k = 1, ..., N-1. There are other definitions with different scaling of X[k], but this form is common in image processing. See also: idct, dct2, idct2, dctmtx. 3.9.6 dct2 ---------- -- Function File: dct2 (X) -- Function File: dct2 (X, M, N) -- Function File: dct2 (X, [M, N]) Compute the 2-D discrete cosine transform of matrix X. If M and N are specified, the input is padded or trimmed to the desired size. See also: dct, idct, idct2. 3.9.7 dctmtx ------------ -- Function File: dctmtx (N) Return the DCT transformation matrix of size N-by-N. If A is an N-by-N matrix, then the following are true: T*A == dct(A), T'*A == idct(A) T*A*T' == dct2(A), T'*A*T == idct2(A) A DCT transformation matrix is useful for doing things like jpeg image compression, in which an 8x8 DCT matrix is applied to non-overlapping blocks throughout an image and only a subblock on the top left of each block is kept. During restoration, the remainder of the block is filled with zeros and the inverse transform is applied to the block. See also: dct, idct, dct2, idct2. 3.9.8 dftmtx ------------ -- Function File: D = dftmtx (N) Compute the N-by-N Fourier transformation matrix. This is the matrix D such that the Fourier transform of a column vector of length N is given by ‘dftmtx(N) * X’ and the inverse Fourier transform is given by ‘inv(dftmtx(N)) * X’. In general this is less efficient than calling the ‘fft’ and ‘ifft’ functions directly. See also: fft, ifft. 3.9.9 digitrevorder ------------------- -- Function File: Y = digitrevorder (X, R) -- Function File: [Y, I] = digitrevorder (X, R) Reorder the elements of the vector X in digit-reversed order. The elements of X are converted to radix R and reversed. The reordered indices of the elements of X are returned in I. See also: bitrevorder, fft, ifft. 3.9.10 dst ---------- -- Function File: Y = dst (X) -- Function File: Y = dst (X, N) Computes the type I discrete sine transform of X. If N is given, then X is padded or trimmed to length N before computing the transform. If X is a matrix, compute the transform along the columns of the the matrix. The discrete sine transform X of x can be defined as follows: N X[k] = sum x[n] sin (pi n k / (N+1) ), k = 1, ..., N n=1 See also: idst. 3.9.11 dwt ---------- -- Function File: [U, V] = dwt (X, WNAME) -- Function File: [U, V] = dwt (X, HP, GP) -- Function File: [U, V] = dwt (X, HP, GP, ...) Discrete wavelet transform (1D). *Inputs* X Signal vector. WNAME Wavelet name. HP Coefficients of low-pass decomposition FIR filter. GP Coefficients of high-pass decomposition FIR filter. *Outputs* U Signal vector of average, approximation. V Signal vector of difference, detail. 3.9.12 fht ---------- -- Function File: M = fht (D) -- Function File: M = fht (D, N) -- Function File: M = fht (D, N, DIM) Calculate the Fast Hartley Transform of real input D. If D is a matrix, the Hartley transform is calculated along the columns by default. The options N and DIM are similar to the options of FFT function. The forward and inverse Hartley transforms are the same (except for a scale factor of 1/N for the inverse Hartley transform), but implemented using different functions. The definition of the forward hartley transform for vector d, m[K] = \sum_{i=0}^{N-1} d[i]*(cos[K*2*pi*i/N] + sin[K*2*pi*i/N]), for 0 <= K < N. m[K] = \sum_{i=0}^{N-1} d[i]*CAS[K*i], for 0 <= K < N. fht(1:4) See also: ifht, fft. 3.9.13 fwht ----------- -- Function File: fwht (X) -- Function File: fwht (X, N) -- Function File: fwht (X, N, ORDER) Compute the Walsh-Hadamard transform of X using the Fast Walsh-Hadamard Transform (FWHT) algorithm. If the input is a matrix, the FWHT is calculated along the columns of X. The number of elements of X must be a power of 2; if not, the input will be extended and filled with zeros. If a second argument is given, the input is truncated or extended to have length N. The third argument specifies the ORDER in which the returned Walsh-Hadamard transform coefficients should be arranged. The ORDER may be any of the following strings: "sequency" The coefficients are returned in sequency order. This is the default if ORDER is not given. "hadamard" The coefficients are returned in Hadamard order. "dyadic" The coefficients are returned in Gray code order. See also: ifwht. 3.9.14 hilbert -------------- -- Function File: H = hilbert (F, N, DIM) Analytic extension of real valued signal. ‘H = hilbert (F)’ computes the extension of the real valued signal F to an analytic signal. If F is a matrix, the transformation is applied to each column. For N-D arrays, the transformation is applied to the first non-singleton dimension. ‘real (H)’ contains the original signal F. ‘imag (H)’ contains the Hilbert transform of F. ‘hilbert (F, N)’ does the same using a length N Hilbert transform. The result will also have length N. ‘hilbert (F, [], DIM)’ or ‘hilbert (F, N, DIM)’ does the same along dimension DIM. 3.9.15 idct ----------- -- Function File: Y = idct (X) -- Function File: Y = idct (X, N) Compute the inverse discrete cosine transform of X. If N is given, then X is padded or trimmed to length N before computing the transform. If X is a matrix, compute the transform along the columns of the the matrix. The transform is faster if X is real-valued and even length. The inverse discrete cosine transform X can be defined as follows: N-1 x[n] = sum w(k) X[k] cos (pi (2n+1) k / 2N ), n = 0, ..., N-1 k=0 with w(0) = sqrt(1/N) and w(k) = sqrt(2/N), k = 1, ..., N-1 See also: dct, dct2, idct2, dctmtx. 3.9.16 idct2 ------------ -- Function File: Y = idct2 (X) -- Function File: Y = idct2 (X, M, N) -- Function File: Y = idct2 (X, [M, N]) Compute the inverse 2-D discrete cosine transform of matrix X. If M and N are specified, the input is either padded or truncated to have M rows and N columns. 3.9.17 idst ----------- -- Function File: Y = idst (X) -- Function File: Y = idst (X, N) Computes the inverse type I discrete sine transform of Y. If N is given, then Y is padded or trimmed to length N before computing the transform. If Y is a matrix, compute the transform along the columns of the the matrix. See also: dst. 3.9.18 ifht ----------- -- Function File: M = ifht (D, N, DIM) Calculate the inverse Fast Hartley Transform of real input D. If D is a matrix, the inverse Hartley transform is calculated along the columns by default. The options N and DIM are similar to the options of FFT function. The forward and inverse Hartley transforms are the same (except for a scale factor of 1/N for the inverse hartley transform), but implemented using different functions. The definition of the forward hartley transform for vector d, m[K] = 1/N \sum_{i=0}^{N-1} d[i]*(cos[K*2*pi*i/N] + sin[K*2*pi*i/N]), for 0 <= K < N. m[K] = 1/N \sum_{i=0}^{N-1} d[i]*CAS[K*i], for 0 <= K < N. ifht(1:4) See also: fht, fft. 3.9.19 ifwht ------------ -- Function File: ifwht (X) -- Function File: ifwht (X, N) -- Function File: ifwht (X, N, ORDER) Compute the inverse Walsh-Hadamard transform of X using the Fast Walsh-Hadamard Transform (FWHT) algorithm. If the input is a matrix, the inverse FWHT is calculated along the columns of X. The number of elements of X must be a power of 2; if not, the input will be extended and filled with zeros. If a second argument is given, the input is truncated or extended to have length N. The third argument specifies the ORDER in which the returned inverse Walsh-Hadamard transform coefficients should be arranged. The ORDER may be any of the following strings: "sequency" The coefficients are returned in sequency order. This is the default if ORDER is not given. "hadamard" The coefficients are returned in Hadamard order. "dyadic" The coefficients are returned in Gray code order. See also: fwht. 3.9.20 rceps ------------ -- Function File: [Y, YM] = rceps (X) Return the cepstrum of the signal X. If X is a matrix, return the cepstrum of each column. If called with two output arguments, the minimum phase reconstruction of the signal X is returned in YM. For example: f0 = 70; Fs = 10000; # 100 Hz fundamental, 10kHz sampling rate a = poly (0.985 * exp (1i * pi * [0.1, -0.1, 0.3, -0.3])); # two formants s = 0.005 * randn (1024, 1); # Noise excitation signal s(1:Fs/f0:length(s)) = 1; # Impulse glottal wave x = filter (1, a, s); # Speech signal [y, ym] = rceps (x .* hanning (1024)); Reference: ‘Programs for Digital Signal Processing’, IEEE Press, John Wiley & Sons, New York, 1979.  File: signal.info, Node: Power Spectrum Analysis, Next: Window Functions, Prev: Transforms, Up: Function Reference 3.10 Power Spectrum Analysis ============================ 3.10.1 __power -------------- -- Function File: [P, W] = __power (B, A) -- Function File: [...] = __power (B, A, NFFT) -- Function File: [...] = __power (B, A, NFFT, FS) -- Function File: [...] = __power (B, A, NFFT, FS, RANGE) -- Function File: [...] = __power (B, A, NFFT, FS, RANGE, UNITS) -- Function File: __power (...) Plot the power spectrum of the given ARMA model. b, a: filter coefficients (b=numerator, a=denominator) nfft is number of points at which to sample the power spectrum Fs is the sampling frequency of x range is ’half’ (default) or ’whole’ units is ’squared’ or ’db’ (default) range and units may be specified any time after the filter, in either order Returns P, the magnitude vector, and w, the frequencies at which it is sampled. If there are no return values requested, then plot the power spectrum and don’t return anything. 3.10.2 ar_psd ------------- -- Function File: ar_psd (A, V) -- Function File: ar_psd (A, V, FREQ) -- Function File: ar_psd (A, V, FREQ, FS) -- Function File: ar_psd (..., RANGE) -- Function File: ar_psd (..., METHOD) -- Function File: ar_psd (..., PLOTTYPE) -- Function File: [PSD, F_OUT] = ar_psd (...) Calculate the power spectrum of the autoregressive model M x(n) = sqrt(v).e(n) + SUM a(k).x(n-k) k=1 where x(n) is the output of the model and e(n) is white noise. This function is intended for use with ‘[a, v, k] = arburg (x, poles, criterion)’ which use the Burg (1968) method to calculate a "maximum entropy" autoregressive model of X. If the FREQ argument is a vector (of frequencies) the spectrum is calculated using the polynomial method and the METHOD argument is ignored. For scalar FREQ, an integer power of 2, or METHOD = "FFT", causes the spectrum to be calculated by FFT. Otherwise, the spectrum is calculated as a polynomial. It may be computationally more efficient to use the FFT method if length of the model is not much smaller than the number of frequency values. The spectrum is scaled so that spectral energy (area under spectrum) is the same as the time-domain energy (mean square of the signal). ARGUMENTS: All but the first two arguments are optional and may be empty. • A list of M=(order+1) autoregressive model coefficients. The first element of "ar_coeffs" is the zero-lag coefficient, which always has a value of 1. • V square of the moving-average coefficient of the AR model. • FREQ frequencies at which power spectral density is calculated, or a scalar indicating the number of uniformly distributed frequency values at which spectral density is calculated. (default = 256) • FS sampling frequency (Hertz) (default=1) CONTROL-STRING ARGUMENTS – each of these arguments is a character string. Control-string arguments can be in any order after the other arguments. Range: ’half’, ’onesided’ : frequency range of the spectrum is from zero up to but not including sample_f/2. Power from negative frequencies is added to the positive side of the spectrum. ’whole’, ’twosided’ : frequency range of the spectrum is -sample_f/2 to sample_f/2, with negative frequencies stored in "wrap around" order after the positive frequencies; e.g. frequencies for a 10-point ’twosided’ spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 ’shift’, ’centerdc’ : same as ’whole’ but with the first half of the spectrum swapped with second half to put the zero-frequency value in the middle. (See "help fftshift". If "freq" is vector, ’shift’ is ignored. If model coefficients "ar_coeffs" are real, the default range is ’half’, otherwise default range is ’whole’. Method: ’fft’: use FFT to calculate power spectrum. ’poly’: calculate power spectrum as a polynomial of 1/z N.B. this argument is ignored if the "freq" argument is a vector. The default is ’poly’ unless the "freq" argument is an integer power of 2. Plot type: ’plot’, ’semilogx’, ’semilogy’, ’loglog’, ’squared’ or ’db’: specifies the type of plot. The default is ’plot’, which means linear-linear axes. ’squared’ is the same as ’plot’. ’dB’ plots "10*log10(psd)". This argument is ignored and a spectrum is not plotted if the caller requires a returned value. RETURNED VALUES: If returned values are not required by the caller, the spectrum is plotted and nothing is returned. • PSD estimate of power-spectral density • F_OUT frequency values REFERENCE [1] Equation 2.28 from Steven M. Kay and Stanley Lawrence Marple Jr.: "Spectrum analysis – a modern perspective", Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981 3.10.3 cohere ------------- -- Function File: [PXX, FREQ] = cohere(X,Y,NFFT,FS,WINDOW,OVERLAP,RANGE,PLOT_TYPE,DETREND) Estimate (mean square) coherence of signals "x" and "y". Use the Welch (1967) periodogram/FFT method. Compatible with Matlab R11 cohere and earlier. See "help pwelch" for description of arguments, hints and references — especially hint (7) for Matlab R11 defaults. 3.10.4 cpsd ----------- -- Function File: [PXX, FREQ] = cpsd (X, Y) -- Function File: [...] = cpsd (X, Y, WINDOW) -- Function File: [...] = cpsd (X, Y, WINDOW, OVERLAP) -- Function File: [...] = cpsd (X, Y, WINDOW, OVERLAP, NFFT) -- Function File: [...] = cpsd (X, Y, WINDOW, OVERLAP, NFFT, FS) -- Function File: [...] = cpsd (X, Y, WINDOW, OVERLAP, NFFT, FS, RANGE) -- Function File: cpsd (...) Estimate cross power spectrum of data X and Y by the Welch (1967) periodogram/FFT method. See also: pwelch. 3.10.5 csd ---------- -- Function File: [PXX,FREQ] = csd(X, Y, NFFT, FS, WINDOW, OVERLAP, RANGE, PLOT_TYPE, DETREND) Estimate cross power spectrum of data "x" and "y" by the Welch (1967) periodogram/FFT method. Compatible with Matlab R11 csd and earlier. See "help pwelch" for description of arguments, hints and references — especially hint (7) for Matlab R11 defaults. 3.10.6 db2pow ------------- -- Function File: db2pow (X) Convert decibels (dB) to power. The power of X is defined as P = ‘10 ^ (x/10)’. If X is a vector, matrix, or N-dimensional array, the power is computed over the elements of X. Example: db2pow ([-10, 0, 10]) ⇒ 0.1000 1.0000 10.0000 See also: pow2db. 3.10.7 mscohere --------------- -- Function File: [PXX, FREQ] = mscohere (X, Y) -- Function File: [...] = mscohere (X, Y, WINDOW) -- Function File: [...] = mscohere (X, Y, WINDOW, OVERLAP) -- Function File: [...] = mscohere (X, Y, WINDOW, OVERLAP, NFFT) -- Function File: [...] = mscohere (X, Y, WINDOW, OVERLAP, NFFT, FS) -- Function File: [...] = mscohere (X, Y, WINDOW, OVERLAP, NFFT, FS, RANGE) -- Function File: mscohere (...) Estimate (mean square) coherence of signals X and Y. Use the Welch (1967) periodogram/FFT method. See also: pwelch. 3.10.8 pburg ------------ -- Function File: [PSD,F_OUT] = pburg(X, POLES, FREQ, FS, RANGE, METHOD, PLOT_TYPE, CRITERION) Calculate Burg maximum-entropy power spectral density. The functions "arburg" and "ar_psd" do all the work. See "help arburg" and "help ar_psd" for further details. ARGUMENTS: All but the first two arguments are optional and may be empty. x [vector] sampled data poles [integer scalar] required number of poles of the AR model freq [real vector] frequencies at which power spectral density is calculated. [integer scalar] number of uniformly distributed frequency values at which spectral density is calculated. [default=256] Fs [real scalar] sampling frequency (Hertz) [default=1] CONTROL-STRING ARGUMENTS – each of these arguments is a character string. Control-string arguments can be in any order after the other arguments. range ’half’, ’onesided’ : frequency range of the spectrum is from zero up to but not including sample_f/2. Power from negative frequencies is added to the positive side of the spectrum. ’whole’, ’twosided’ : frequency range of the spectrum is -sample_f/2 to sample_f/2, with negative frequencies stored in "wrap around" order after the positive frequencies; e.g. frequencies for a 10-point ’twosided’ spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 ’shift’, ’centerdc’ : same as ’whole’ but with the first half of the spectrum swapped with second half to put the zero-frequency value in the middle. (See "help fftshift". If "freq" is vector, ’shift’ is ignored. If model coefficients "ar_coeffs" are real, the default range is ’half’, otherwise default range is ’whole’. method ’fft’: use FFT to calculate power spectral density. ’poly’: calculate spectral density as a polynomial of 1/z N.B. this argument is ignored if the "freq" argument is a vector. The default is ’poly’ unless the "freq" argument is an integer power of 2. plot_type ’plot’, ’semilogx’, ’semilogy’, ’loglog’, ’squared’ or ’db’: specifies the type of plot. The default is ’plot’, which means linear-linear axes. ’squared’ is the same as ’plot’. ’dB’ plots "10*log10(psd)". This argument is ignored and a spectrum is not plotted if the caller requires a returned value. criterion [optional string arg] model-selection criterion. Limits the number of poles so that spurious poles are not added when the whitened data has no more information in it (see Kay & Marple, 1981). Recognized values are ’AKICc’ – approximate corrected Kullback information criterion (recommended), ’KIC’ – Kullback information criterion ’AICc’ – corrected Akaike information criterion ’AIC’ – Akaike information criterion ’FPE’ – final prediction error" criterion The default is to NOT use a model-selection criterion RETURNED VALUES: If return values are not required by the caller, the spectrum is plotted and nothing is returned. psd [real vector] power-spectral density estimate f_out [real vector] frequency values HINTS This function is a wrapper for arburg and ar_psd. See "help arburg", "help ar_psd". 3.10.9 pow2db ------------- -- Function File: pow2db (X) Convert power to decibels (dB). The decibel value of X is defined as D = ‘10 * log10 (x)’. If X is a vector, matrix, or N-dimensional array, the decibel value is computed over the elements of X. Examples: pow2db ([0, 10, 100]) ⇒ -Inf 10 20 See also: db2pow. 3.10.10 pwelch -------------- -- Function File: [SPECTRA,FREQ] = pwelch(X, WINDOW, OVERLAP, NFFT, FS, RANGE, PLOT_TYPE, DETREND, SLOPPY) Estimate power spectral density of data "x" by the Welch (1967) periodogram/FFT method. All arguments except "x" are optional. The data is divided into segments. If "window" is a vector, each segment has the same length as "window" and is multiplied by "window" before (optional) zero-padding and calculation of its periodogram. If "window" is a scalar, each segment has a length of "window" and a Hamming window is used. The spectral density is the mean of the periodograms, scaled so that area under the spectrum is the same as the mean square of the data. This equivalence is supposed to be exact, but in practice there is a mismatch of up to 0.5% when comparing area under a periodogram with the mean square of the data. [spectra,freq] = pwelch(x,y,window,overlap,Nfft,Fs, range,plot_type,detrend,sloppy,results) Two-channel spectrum analyser. Estimate power spectral density, cross- spectral density, transfer function and/or coherence functions of time- series input data "x" and output data "y" by the Welch (1967) periodogram/FFT method. pwelch treats the second argument as "y" if there is a control-string argument "cross", "trans", "coher" or "ypower"; "power" does not force the 2nd argument to be treated as "y". All other arguments are optional. All spectra are returned in matrix "spectra". [spectra,Pxx_ci,freq] = pwelch(x,window,overlap,Nfft,Fs,conf, range,plot_type,detrend,sloppy) [spectra,Pxx_ci,freq] = pwelch(x,y,window,overlap,Nfft,Fs,conf, range,plot_type,detrend,sloppy,results) Estimates confidence intervals for the spectral density. See Hint (7) below for compatibility options. Confidence level "conf" is the 6th or 7th numeric argument. If "results" control-string arguments are used, one of them must be "power" when the "conf" argument is present; pwelch can estimate confidence intervals only for the power spectrum of the "x" data. It does not know how to estimate confidence intervals of the cross-power spectrum, transfer function or coherence; if you can suggest a good method, please send a bug report. ARGUMENTS All but the first argument are optional and may be empty, except that the "results" argument may require the second argument to be "y". x [non-empty vector] system-input time-series data y [non-empty vector] system-output time-series data window [real vector] of window-function values between 0 and 1; the data segment has the same length as the window. Default window shape is Hamming. [integer scalar] length of each data segment. The default value is window=sqrt(length(x)) rounded up to the nearest integer power of 2; see ’sloppy’ argument. overlap [real scalar] segment overlap expressed as a multiple of window or segment length. 0 <= overlap < 1, The default is overlap=0.5 . Nfft [integer scalar] Length of FFT. The default is the length of the "window" vector or has the same value as the scalar "window" argument. If Nfft is larger than the segment length, "seg_len", the data segment is padded with "Nfft-seg_len" zeros. The default is no padding. Nfft values smaller than the length of the data segment (or window) are ignored silently. Fs [real scalar] sampling frequency (Hertz); default=1.0 conf [real scalar] confidence level between 0 and 1. Confidence intervals of the spectral density are estimated from scatter in the periodograms and are returned as Pxx_ci. Pxx_ci(:,1) is the lower bound of the confidence interval and Pxx_ci(:,2) is the upper bound. If there are three return values, or conf is an empty matrix, confidence intervals are calculated for conf=0.95 . If conf is zero or is not given, confidence intervals are not calculated. Confidence intervals can be obtained only for the power spectral density of x; nothing else. CONTROL-STRING ARGUMENTS – each of these arguments is a character string. Control-string arguments must be after the other arguments but can be in any order. range ’half’, ’onesided’ : frequency range of the spectrum is zero up to but not including Fs/2. Power from negative frequencies is added to the positive side of the spectrum, but not at zero or Nyquist (Fs/2) frequencies. This keeps power equal in time and spectral domains. See reference [2]. ’whole’, ’twosided’ : frequency range of the spectrum is -Fs/2 to Fs/2, with negative frequencies stored in "wrap around" order after the positive frequencies; e.g. frequencies for a 10-point ’twosided’ spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 ’shift’, ’centerdc’ : same as ’whole’ but with the first half of the spectrum swapped with second half to put the zero-frequency value in the middle. (See "help fftshift". If data (x and y) are real, the default range is ’half’, otherwise default range is ’whole’. plot_type ’plot’, ’semilogx’, ’semilogy’, ’loglog’, ’squared’ or ’db’: specifies the type of plot. The default is ’plot’, which means linear-linear axes. ’squared’ is the same as ’plot’. ’dB’ plots "10*log10(psd)". This argument is ignored and a spectrum is not plotted if the caller requires a returned value. detrend ’no-strip’, ’none’ – do NOT remove mean value from the data ’short’, ’mean’ – remove the mean value of each segment from each segment of the data. ’linear’, – remove linear trend from each segment of the data. ’long-mean’ – remove the mean value from the data before splitting it into segments. This is the default. sloppy ’sloppy’: FFT length is rounded up to the nearest integer power of 2 by zero padding. FFT length is adjusted after addition of padding by explicit Nfft argument. The default is to use exactly the FFT and window/ segment lengths specified in argument list. results specifies what results to return (in the order specified and as many as desired). ’power’ calculate power spectral density of "x" ’cross’ calculate cross spectral density of "x" and "y" ’trans’ calculate transfer function of a system with input "x" and output "y" ’coher’ calculate coherence function of "x" and "y" ’ypower’ calculate power spectral density of "y" The default is ’power’, with argument "y" omitted. RETURNED VALUES: If return values are not required by the caller, the results are plotted and nothing is returned. spectra [real-or-complex matrix] columns of the matrix contain results in the same order as specified by "results" arguments. Each column contains one of the result vectors. Pxx_ci [real matrix] estimate of confidence interval for power spectral density of x. First column is the lower bound. Second column is the upper bound. freq [real column vector] frequency values HINTS 1. EMPTY ARGS: if you don’t want to use an optional argument you can leave it empty by writing its value as []. 2. FOR BEGINNERS: The profusion of arguments may make pwelch difficult to use, and an unskilled user can easily produce a meaningless result or can easily mis-interpret the result. With real data "x" and sampling frequency "Fs", the easiest and best way for a beginner to use pwelch is probably "pwelch(x,[],[],[],Fs)". Use the "window" argument to control the length of the spectrum vector. For real data and integer scalar M, "pwelch(x,2*M,[],[],Fs)" gives an M+1 point spectrum. Run "demo pwelch" (octave only). 3. WINDOWING FUNCTIONS: Without a window function, sharp spectral peaks can have strong sidelobes because the FFT of a data in a segment is in effect convolved with a rectangular window. A window function which tapers off (gradually) at the ends produces much weaker sidelobes in the FFT. Hann (hanning), hamming, bartlett, blackman, flattopwin etc are available as separate Matlab/sigproc or Octave functions. The sidelobes of the Hann window have a roll-off rate of 60dB/decade of frequency. The first sidelobe of the Hamming window is suppressed and is about 12dB lower than the first Hann sidelobe, but the roll-off rate is only 20dB/decade. You can inspect the FFT of a Hann window by plotting "abs(fft(postpad(hanning(256),4096,0)))". The default window is Hamming. 4. ZERO PADDING: Zero-padding reduces the frequency step in the spectrum, and produces an artificially smoothed spectrum. For example, "Nfft=2*length(window)" gives twice as many frequency values, but adjacent PSD (power spectral density) values are not independent; adjacent PSD values are independent if "Nfft=length(window)", which is the default value of Nfft. 5. REMOVING MEAN FROM SIGNAL: If the mean is not removed from the signal there is a large spectral peak at zero frequency and the sidelobes of this peak are likely to swamp the rest of the spectrum. For this reason, the default behavior is to remove the mean. However, the matlab pwelch does not do this. 6. WARNING ON CONFIDENCE INTERVALS Confidence intervals are obtained by measuring the sample variance of the periodograms and assuming that the periodograms have a Gaussian probability distribution. This assumption is not accurate. If, for example, the data (x) is Gaussian, the periodogram has a Rayleigh distribution. However, the confidence intervals may still be useful. 7. COMPATIBILITY WITH Matlab R11, R12, etc When used without the second data (y) argument, arguments are compatible with the pwelch of Matlab R12, R13, R14, 2006a and 2006b except that 1) overlap is expressed as a multiple of window length — effect of overlap scales with window length 2) default values of length(window), Nfft and Fs are more sensible, and 3) Goertzel algorithm is not available so Nfft cannot be an array of frequencies as in Matlab 2006b. Pwelch has four persistent Matlab-compatibility levels. Calling pwelch with an empty first argument sets the order of arguments and defaults specified above in the USAGE and ARGUMENTS section of this documentation. prev_compat=pwelch([]); [Pxx,f]=pwelch(x,window,overlap,Nfft,Fs,conf,...); Calling pwelch with a single string argument (as described below) gives compatibility with Matlab R11 or R12, or the R14 spectrum.welch defaults. The returned value is the PREVIOUS compatibility string. Matlab R11: For compatibility with the Matlab R11 pwelch: prev_compat=pwelch('R11-'); [Pxx,f]=pwelch(x,Nfft,Fs,window,overlap,conf,range,units); %% units of overlap are "number of samples" %% defaults: Nfft=min(length(x),256), Fs=2*pi, length(window)=Nfft, %% window=Hanning, do not detrend, %% N.B. "Sloppy" is not available. Matlab R12: For compatibility with Matlab R12 to 2006a pwelch: prev_compat=pwelch('R12+'); [Pxx,f]=pwelch(x,window,overlap,nfft,Fs,...); %% units of overlap are "number of samples" %% defaults: length(window)==length(x)/8, window=Hamming, %% Nfft=max(256,NextPow2), Fs=2*pi, do not detrend %% NextPow2 is the next power of 2 greater than or equal to the %% window length. "Sloppy", "conf" are not available. Default %% window length gives very poor amplitude resolution. To adopt defaults of the Matlab R14 "spectrum.welch" spectrum object associated "psd" method. prev_compat=pwelch('psd'); [Pxx,f] = pwelch(x,window,overlap,Nfft,Fs,conf,...); %% overlap is expressed as a percentage of window length, %% defaults: length(window)==64, Nfft=max(256,NextPow2), Fs=2*pi %% do not detrend %% NextPow2 is the next power of 2 greater than or equal to the %% window length. "Sloppy" is not available. %% Default window length gives coarse frequency resolution. REFERENCES [1] Peter D. Welch (June 1967): "The use of fast Fourier transform for the estimation of power spectra: a method based on time averaging over short, modified periodograms." IEEE Transactions on Audio Electroacoustics, Vol AU-15(6), pp 70-73 [2] William H. Press and Saul A. Teukolsky and William T. Vetterling and Brian P. Flannery", "Numerical recipes in C, The art of scientific computing", 2nd edition, Cambridge University Press, 2002 — Section 13.7. 3.10.11 pyulear --------------- -- Function File: [psd,f_out] = pyulear(x,poles,freq,Fs,range,method,plot_type) Calculates a Yule-Walker autoregressive (all-pole) model of the data "x" and computes the power spectrum of the model. This is a wrapper for functions "aryule" and "ar_psd" which perform the argument checking. See "help aryule" and "help ar_psd" for further details. ARGUMENTS: All but the first two arguments are optional and may be empty. x [vector] sampled data poles [integer scalar] required number of poles of the AR model freq [real vector] frequencies at which power spectral density is calculated [integer scalar] number of uniformly distributed frequency values at which spectral density is calculated. [default=256] Fs [real scalar] sampling frequency (Hertz) [default=1] CONTROL-STRING ARGUMENTS – each of these arguments is a character string. Control-string arguments can be in any order after the other arguments. range ’half’, ’onesided’ : frequency range of the spectrum is from zero up to but not including sample_f/2. Power from negative frequencies is added to the positive side of the spectrum. ’whole’, ’twosided’ : frequency range of the spectrum is -sample_f/2 to sample_f/2, with negative frequencies stored in "wrap around" order after the positive frequencies; e.g. frequencies for a 10-point ’twosided’ spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 ’shift’, ’centerdc’ : same as ’whole’ but with the first half of the spectrum swapped with second half to put the zero-frequency value in the middle. (See "help fftshift". If "freq" is vector, ’shift’ is ignored. If model coefficients "ar_coeffs" are real, the default range is ’half’, otherwise default range is ’whole’. method ’fft’: use FFT to calculate power spectrum. ’poly’: calculate power spectrum as a polynomial of 1/z N.B. this argument is ignored if the "freq" argument is a vector. The default is ’poly’ unless the "freq" argument is an integer power of 2. plot_type ’plot’, ’semilogx’, ’semilogy’, ’loglog’, ’squared’ or ’db’: specifies the type of plot. The default is ’plot’, which means linear-linear axes. ’squared’ is the same as ’plot’. ’dB’ plots "10*log10(psd)". This argument is ignored and a spectrum is not plotted if the caller requires a returned value. RETURNED VALUES: If return values are not required by the caller, the spectrum is plotted and nothing is returned. psd [real vector] power-spectrum estimate f_out [real vector] frequency values HINTS This function is a wrapper for aryule and ar_psd. See "help aryule", "help ar_psd". 3.10.12 tfe ----------- -- Function File: [Pxx,freq] = tfe(x,y,Nfft,Fs,window,overlap,range,plot_type,detrend) Estimate transfer function of system with input "x" and output "y". Use the Welch (1967) periodogram/FFT method. Compatible with Matlab R11 tfe and earlier. See "help pwelch" for description of arguments, hints and references — especially hint (7) for Matlab R11 defaults. 3.10.13 tfestimate ------------------ -- Function File: tfestimate (X, Y) -- Function File: tfestimate (X, Y, WINDOW) -- Function File: tfestimate (X, Y, WINDOW, OVERLAP) -- Function File: tfestimate (X, Y, WINDOW, OVERLAP, NFFT) -- Function File: tfestimate (X, Y, WINDOW, OVERLAP, NFFT, FS) -- Function File: tfestimate (X, Y, WINDOW, OVERLAP, NFFT, FS, RANGE) -- Function File: [PXX, FREQ] = tfestimate (...) Estimate transfer function of system with input X and output Y. Use the Welch (1967) periodogram/FFT method. See also: pwelch.  File: signal.info, Node: Window Functions, Next: System Identification, Prev: Power Spectrum Analysis, Up: Function Reference 3.11 Window Functions ===================== 3.11.1 barthannwin ------------------ -- Function File: barthannwin (M) Return the filter coefficients of a modified Bartlett-Hann window of length M. See also: rectwin, bartlett. 3.11.2 blackmanharris --------------------- -- Function File: blackmanharris (M) -- Function File: blackmanharris (M, "periodic") -- Function File: blackmanharris (M, "symmetric") Return the filter coefficients of a Blackman-Harris window of length M. If the optional argument ‘"periodic"’ is given, the periodic form of the window is returned. This is equivalent to the window of length M+1 with the last coefficient removed. The optional argument ‘"symmetric"’ is equivalent to not specifying a second argument. See also: rectwin, bartlett. 3.11.3 blackmannuttall ---------------------- -- Function File: blackmannuttall (M) -- Function File: blackmannuttall (M, "periodic") -- Function File: blackmannuttall (M, "symmetric") Return the filter coefficients of a Blackman-Nuttall window of length M. If the optional argument ‘"periodic"’ is given, the periodic form of the window is returned. This is equivalent to the window of length M+1 with the last coefficient removed. The optional argument ‘"symmetric"’ is equivalent to not specifying a second argument. See also: nuttallwin, kaiser. 3.11.4 bohmanwin ---------------- -- Function File: bohmanwin (M) Return the filter coefficients of a Bohman window of length M. See also: rectwin, bartlett. 3.11.5 boxcar ------------- -- Function File: boxcar (M) Return the filter coefficients of a rectangular window of length M. 3.11.6 chebwin -------------- -- Function File: chebwin (M) -- Function File: chebwin (M, AT) Return the filter coefficients of a Dolph-Chebyshev window of length M. The Fourier transform of the window has a stop-band attenuation of AT dB. The default attenuation value is 100 dB. For the definition of the Chebyshev window, see * Peter Lynch, "The Dolph-Chebyshev Window: A Simple Optimal Filter", Monthly Weather Review, Vol. 125, pp. 655-660, April 1997. (http://www.maths.tcd.ie/~plynch/Publications/Dolph.pdf) * C. Dolph, "A current distribution for broadside arrays which optimizes the relationship between beam width and side-lobe level", Proc. IEEE, 34, pp. 335-348. The window is described in frequency domain by the expression: Cheb(m-1, beta * cos(pi * k/m)) W(k) = ------------------------------- Cheb(m-1, beta) with beta = cosh(1/(m-1) * acosh(10^(at/20)) and Cheb(m,x) denoting the m-th order Chebyshev polynomial calculated at the point x. Note that the denominator in W(k) above is not computed, and after the inverse Fourier transform the window is scaled by making its maximum value unitary. See also: kaiser. 3.11.7 flattopwin ----------------- -- Function File: flattopwin (M) -- Function File: flattopwin (M, "periodic") -- Function File: flattopwin (M, "symmetric") Return the filter coefficients of a Flat Top window of length M. The Flat Top window is defined by the function f(w): f(w) = 1 - 1.93 cos(2 pi w) + 1.29 cos(4 pi w) - 0.388 cos(6 pi w) + 0.0322cos(8 pi w) where w = i/(m-1) for i=0:m-1 for a symmetric window, or w = i/m for i=0:m-1 for a periodic window. The default is symmetric. The returned window is normalized to a peak of 1 at w = 0.5. This window has low pass-band ripple, but high bandwidth. According to [1]: The main use for the Flat Top window is for calibration, due to its negligible amplitude errors. [1] Gade, S; Herlufsen, H; (1987) "Use of weighting functions in DFT/FFT analysis (Part I)", Bruel & Kjaer Technical Review No.3. 3.11.8 gaussian --------------- -- Function File: gaussian (M) -- Function File: gaussian (M, A) Return a Gaussian convolution window of length M. The width of the window is inversely proportional to the parameter A. Use larger A for a narrower window. Use larger M for longer tails. w = exp ( -(a*x)^2/2 ) for x = linspace ( -(m-1)/2, (m-1)/2, m ). Width a is measured in frequency units (sample rate/num samples). It should be f when multiplying in the time domain, but 1/f when multiplying in the frequency domain (for use in convolutions). 3.11.9 gausswin --------------- -- Function File: gausswin (M) -- Function File: gausswin (M, A) Return the filter coefficients of a Gaussian window of length M. The width of the window is inversely proportional to the parameter A. Use larger A for a narrow window. Use larger M for a smoother curve. w = exp ( -(a*x)^2/2 ) for x = linspace(-(m-1)/m, (m-1)/m, m) 3.11.10 hann ------------ -- Function File: hann (M) -- Function File: hann (M, "periodic") -- Function File: hann (M, "symmetric") Return the filter coefficients of a Hanning window of length M. If the optional argument ‘"periodic"’ is given, the periodic form of the window is returned. This is equivalent to the window of length M+1 with the last coefficient removed. The optional argument ‘"symmetric"’ is equivalent to not specifying a second argument. This function exists for MATLAB compatibility only, and is equivalent to ‘hanning (M)’. See also: hanning. 3.11.11 kaiser -------------- -- Function File: kaiser (M) -- Function File: kaiser (M, BETA) Return the filter coefficients of a Kaiser window of length M. The Fourier transform of the window has a stop-band attenuation that is derived from the parameter BETA. For the definition of the Kaiser window, see A. V. Oppenheim & R. W. Schafer, "Discrete-Time Signal Processing". The continuous version of width m centered about x=0 is: besseli(0, beta * sqrt(1-(2*x/m).^2)) k(x) = -------------------------------------, m/2 <= x <= m/2 besseli(0, beta) See also: kaiserord. 3.11.12 nuttallwin ------------------ -- Function File: nuttallwin (M) -- Function File: nuttallwin (M, "periodic") -- Function File: nuttallwin (M, "symmetric") Return the filter coefficients of a Blackman-Harris window defined by Nuttall of length M. If the optional argument ‘"periodic"’ is given, the periodic form of the window is returned. This is equivalent to the window of length M+1 with the last coefficient removed. The optional argument ‘"symmetric"’ is equivalent to not specifying a second argument. See also: blackman, blackmanharris. 3.11.13 parzenwin ----------------- -- Function File: parzenwin (M) Return the filter coefficients of a Parzen window of length M. See also: rectwin, bartlett. 3.11.14 rectwin --------------- -- Function File: rectwin (M) Return the filter coefficients of a rectangular window of length M. See also: boxcar, hamming, hanning. 3.11.15 triang -------------- -- Function File: triang (M) Return the filter coefficients of a triangular window of length M. Unlike the Bartlett window, ‘triang’ does not go to zero at the edges of the window. For odd M, ‘triang (M)’ is equal to ‘bartlett (M + 2)’ except for the zeros at the edges of the window. See also: bartlett. 3.11.16 tukeywin ---------------- -- Function File: tukeywin (M) -- Function File: tukeywin (M, R) Return the filter coefficients of a Tukey window (also known as the cosine-tapered window) of length M. R defines the ratio between the constant section and and the cosine section. It has to be between 0 and 1. The function returns a Hanning window for R equal to 1 and a rectangular window for R equal to 0. The default value of R is 1/2. For a definition of the Tukey window, see e.g. Fredric J. Harris, "On the Use of Windows for Harmonic Analysis with the Discrete Fourier Transform, Proceedings of the IEEE", Vol. 66, No. 1, January 1978, Page 67, Equation 38. See also: hanning. 3.11.17 ultrwin --------------- -- Function File: [W, XMU] = ultrwin (M, MU, BETA) -- Function File: [W, XMU] = ultrwin (M, MU, ATT, "att") -- Function File: [W, XMU] = ultrwin (M, MU, LATT, "latt") -- Function File: W = ultrwin (M, MU, XMU, "xmu") Return the coefficients of an Ultraspherical window of length M. The parameter MU controls the window’s Fourier transform’s side-lobe to side-lobe ratio, and the third given parameter controls the transform’s main-lobe width/side-lobe-ratio; normalize W such that the central coefficient(s) value is unitary. By default, the third parameter is BETA, which sets the main lobe width to BETA times that of a rectangular window. Alternatively, giving ATT or LATT sets the ripple ratio at the first or last side-lobe respectively, or giving XMU sets the (un-normalized) window’s Fourier transform according to its canonical definition: (MU) W(k) = C [ XMU cos(pi k/M) ], k = 0, 1, ..., M-1, M-1 where C is the Ultraspherical (a.k.a. Gegenbauer) polynomial, which can be defined using the recurrence relationship: (l) 1 (l) (l) C (x) = - [ 2x(m + l - 1) C (x) - (m + 2l - 2) C (x) ] m m m-1 m-2 (l) (l) for m an integer > 1, and C (x) = 1, C (x) = 2lx. 0 1 For given BETA, ATT, or LATT, the corresponding (determined) value of XMU is also returned. The Dolph-Chebyshev and Saramaki windows are special cases of the Ultraspherical window, with MU set to 0 and 1 respectively. Note that when not giving XMU, stability issues may occur with MU <= -1.5. For further information about the window, see • Kabal, P., 2009: Time Windows for Linear Prediction of Speech. Technical Report, Dept. Elec. & Comp. Eng., McGill University. • Bergen, S., Antoniou, A., 2004: Design of Ultraspherical Window Functions with Prescribed Spectral Characteristics. Proc. JASP, 13/13, pp. 2053-2065. • Streit, R., 1984: A two-parameter family of weights for nonrecursive digital filters and antennas. Trans. ASSP, 32, pp. 108-118. See also: chebwin, kaiser. 3.11.18 welchwin ---------------- -- Function File: welchwin (M) -- Function File: welchwin (M, "periodic") -- Function File: welchwin (M, "symmetric") Return the filter coefficients of a Welch window of length M. The Welch window is given by W(n)=1-(n/N-1)^2, n=[0,1, ... M-1]. The optional argument specifies a "symmetric" window (the default) or a "periodic" window. A symmetric window has zero at each end and maximum in the middle, and the length must be an integer greater than 2. The variable N in the formula above is ‘(M-1)/2’. A periodic window wraps around the cyclic interval [0,1, ... M-1], and is intended for use with the DFT. The length must be an integer greater than 1. The variable N in the formula above is ‘M/2’. See also: blackman, kaiser. 3.11.19 window -------------- -- Function File: W = window (F, M) -- Function File: W = window (F, M, OPTS) Create an M-point window from the function F. The function F can be for example ‘@blackman’. Any additional arguments OPT are passed to the windowing function.  File: signal.info, Node: System Identification, Next: Sample Rate Change, Prev: Window Functions, Up: Function Reference 3.12 System Identification ========================== 3.12.1 arburg ------------- -- Function File: [A, V, K] = arburg (X, POLES) -- Function File: [A, V, K] = arburg (X, POLES, CRITERION) Calculate coefficients of an autoregressive (AR) model of complex data X using the whitening lattice-filter method of Burg (1968). The inverse of the model is a moving-average filter which reduces X to white noise. The power spectrum of the AR model is an estimate of the maximum entropy power spectrum of the data. The function ‘ar_psd’ calculates the power spectrum of the AR model. ARGUMENTS: • X sampled data • POLES number of poles in the AR model or limit to the number of poles if a valid CRITERION is provided. • CRITERION model-selection criterion. Limits the number of poles so that spurious poles are not added when the whitened data has no more information in it (see Kay & Marple, 1981). Recognized values are ’AKICc’ – approximate corrected Kullback information criterion (recommended), ’KIC’ – Kullback information criterion ’AICc’ – corrected Akaike information criterion ’AIC’ – Akaike information criterion ’FPE’ – final prediction error" criterion The default is to NOT use a model-selection criterion RETURNED VALUES: • A list of (P+1) autoregression coefficients; for data input x(n) and white noise e(n), the model is P+1 x(n) = sqrt(v).e(n) + SUM a(k).x(n-k) k=1 V mean square of residual noise from the whitening operation of the Burg lattice filter. • K reflection coefficients defining the lattice-filter embodiment of the model HINTS: (1) arburg does not remove the mean from the data. You should remove the mean from the data if you want a power spectrum. A non-zero mean can produce large errors in a power-spectrum estimate. See "help detrend". (2) If you don’t know what the value of "poles" should be, choose the largest (reasonable) value you could want and use the recommended value, criterion=’AKICc’, so that arburg can find it. E.g. arburg(x,64,’AKICc’) The AKICc has the least bias and best resolution of the available model-selection criteria. (3) Autoregressive and moving-average filters are stored as polynomials which, in matlab, are row vectors. NOTE ON SELECTION CRITERION: AIC, AICc, KIC and AKICc are based on information theory. They attempt to balance the complexity (or length) of the model against how well the model fits the data. AIC and KIC are biased estimates of the asymmetric and the symmetric Kullback-Leibler divergence respectively. AICc and AKICc attempt to correct the bias. See reference [4]. REFERENCES: [1] John Parker Burg (1968) "A new analysis technique for time series data", NATO advanced study Institute on Signal Processing with Emphasis on Underwater Acoustics, Enschede, Netherlands, Aug. 12-23, 1968. [2] Steven M. Kay and Stanley Lawrence Marple Jr.: "Spectrum analysis – a modern perspective", Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981 [3] William H. Press and Saul A. Teukolsky and William T. Vetterling and Brian P. Flannery "Numerical recipes in C, The art of scientific computing", 2nd edition, Cambridge University Press, 2002 — Section 13.7. [4] Abd-Krim Seghouane and Maiza Bekara "A small sample model selection criterion based on Kullback’s symmetric divergence", IEEE Transactions on Signal Processing, Vol. 52(12), pp 3314-3323, Dec. 2004 See also: ar_psd. 3.12.2 aryule ------------- -- Function File: A = aryule (X, P) -- Function File: [A, V, K] = aryule (X, P) Fit an AR (P)-model with Yule-Walker estimates. X data vector to estimate A AR coefficients V variance of white noise K reflection coefficients for use in lattice filter The power spectrum of the resulting filter can be plotted with pyulear(x, p), or you can plot it directly with ar_psd(a,v,...). See also: pyulear, power, freqz, impz – for observing characteristics of the model arburg – for alternative spectral estimators Example: Use example from arburg, but substitute aryule for arburg. Note: Orphanidis ’85 claims lattice filters are more tolerant of truncation errors, which is why you might want to use them. However, lacking a lattice filter processor, I haven’t tested that the lattice filter coefficients are reasonable. 3.12.3 invfreq -------------- -- Function File: [B,A] = invfreq(H,F,nB,nA) -- : [B,A] = invfreq(H,F,nB,nA,W) -- : [B,A] = invfreq(H,F,nB,nA,W,[],[],plane) -- : [B,A] = invfreq(H,F,nB,nA,W,iter,tol,plane) Fit filter B(z)/A(z) or B(s)/A(s) to complex frequency response at frequency points F. A and B are real polynomial coefficients of order nA and nB respectively. Optionally, the fit-errors can be weighted vs frequency according to the weights W. Also, the transform plane can be specified as either ’s’ for continuous time or ’z’ for discrete time. ’z’ is chosen by default. Eventually, Steiglitz-McBride iterations will be specified by iter and tol. H: desired complex frequency response It is assumed that A and B are real polynomials, hence H is one-sided. F: vector of frequency samples in radians nA: order of denominator polynomial A nB: order of numerator polynomial B plane=’z’: F on unit circle (discrete-time spectra, z-plane design) plane=’s’: F on jw axis (continuous-time spectra, s-plane design) H(k) = spectral samples of filter frequency response at points zk, where zk=exp(sqrt(-1)*F(k)) when plane=’z’ (F(k) in [0,.5]) and zk=(sqrt(-1)*F(k)) when plane=’s’ (F(k) nonnegative) Example: [B,A] = butter(12,1/4); [H,w] = freqz(B,A,128); [Bh,Ah] = invfreq(H,F,4,4); Hh = freqz(Bh,Ah); disp(sprintf('||frequency response error|| = %f',norm(H-Hh))); References: J. O. Smith, "Techniques for Digital Filter Design and System Identification with Application to the Violin, Ph.D. Dissertation, Elec. Eng. Dept., Stanford University, June 1983, page 50; or, http://ccrma.stanford.edu/~jos/filters/FFT_Based_Equation_Error_Method.html 3.12.4 invfreqs --------------- -- Function File: [B,A] = invfreqs(H,F,nB,nA) -- : [B,A] = invfreqs(H,F,nB,nA,W) -- : [B,A] = invfreqs(H,F,nB,nA,W,iter,tol,'trace') Fit filter B(s)/A(s)to the complex frequency response H at frequency points F. A and B are real polynomial coefficients of order nA and nB. Optionally, the fit-errors can be weighted vs frequency according to the weights W. Note: all the guts are in invfreq.m H: desired complex frequency response F: frequency (must be same length as H) nA: order of the denominator polynomial A nB: order of the numerator polynomial B W: vector of weights (must be same length as F) Example: B = [1/2 1]; A = [1 1]; w = linspace(0,4,128); H = freqs(B,A,w); [Bh,Ah] = invfreqs(H,w,1,1); Hh = freqs(Bh,Ah,w); plot(w,[abs(H);abs(Hh)]) legend('Original','Measured'); err = norm(H-Hh); disp(sprintf('L2 norm of frequency response error = %f',err)); 3.12.5 invfreqz --------------- -- Function File: [B,A] = invfreqz(H,F,nB,nA) -- : [B,A] = invfreqz(H,F,nB,nA,W) -- : [B,A] = invfreqz(H,F,nB,nA,W,iter,tol,'trace') Fit filter B(z)/A(z)to the complex frequency response H at frequency points F. A and B are real polynomial coefficients of order nA and nB. Optionally, the fit-errors can be weighted vs frequency according to the weights W. Note: all the guts are in invfreq.m H: desired complex frequency response F: normalized frequency (0 to pi) (must be same length as H) nA: order of the denominator polynomial A nB: order of the numerator polynomial B W: vector of weights (must be same length as F) Example: [B,A] = butter(4,1/4); [H,F] = freqz(B,A); [Bh,Ah] = invfreq(H,F,4,4); Hh = freqz(Bh,Ah); disp(sprintf('||frequency response error|| = %f',norm(H-Hh))); 3.12.6 levinson --------------- -- Function File: [A, V, REF] = levinson (ACF) -- Function File: [...] = levinson (ACF, P) Use the Durbin-Levinson algorithm to solve: toeplitz(acf(1:p)) * x = -acf(2:p+1). The solution [1, x’] is the denominator of an all pole filter approximation to the signal x which generated the autocorrelation function acf. acf is the autocorrelation function for lags 0 to p. p defaults to length(acf)-1. Returns a=[1, x’] the denominator filter coefficients. v= variance of the white noise = square of the numerator constant ref = reflection coefficients = coefficients of the lattice implementation of the filter Use freqz(sqrt(v),a) to plot the power spectrum. REFERENCE [1] Steven M. Kay and Stanley Lawrence Marple Jr.: "Spectrum analysis – a modern perspective", Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981 3.12.7 lpc ---------- -- Function File: A = lpc (X) -- Function File: A = lpc (X, P) -- Function File: [A, G] = lpc (...) -- Function File: [A, G] = lpc (X, P) Determines the forward linear predictor by minimizing the prediction error in the least squares sense. Use the Durbin-Levinson algorithm to solve the Yule-Walker equations obtained by the autocorrelation of the input signal. X is a data vector used to estimate the lpc model of P-th order, given by the prediction polynomial ‘A = [1 A(2) ... A(P+1)]’. If P is not provided, ‘length(P) - 1’ is used as default. X might also be a matrix, in which case each column is regarded as a separate signal. ‘lpc’ will return a model estimate for each column of X. G is the variance (power) of the prediction error for each signal in X. See also: aryule,levinson.  File: signal.info, Node: Sample Rate Change, Next: Pulse Metrics, Prev: System Identification, Up: Function Reference 3.13 Sample Rate Change ======================= 3.13.1 data2fun --------------- -- Function File: [FHANDLE, FULLNAME] = data2fun (TI, YI) -- Function File: [...] = data2fun (..., PROPERTY, VALUE) Create a vectorized function based on data samples using interpolation. The values given in YI (N-by-k matrix) correspond to evaluations of the function y(t) at the points TI (N-by-1 matrix). The data is interpolated and the function handle to the generated interpolant is returned. The function accepts PROPERTY-VALUE pairs described below. ‘file’ Code is generated and .m file is created. The VALUE contains the name of the function. The returned function handle is a handle to that file. If VALUE is empty, then a name is automatically generated using ‘tempname’ and the file is created in the current directory. VALUE must not have an extension, since .m will be appended. Numerical values used in the function are stored in a .mat file with the same name as the function. ‘interp’ Type of interpolation. See ‘interp1’. See also: interp1. 3.13.2 decimate --------------- -- Function File: Y = decimate (X, Q) -- Function File: Y = decimate (X, Q, N) -- Function File: Y = decimate (..., "fir") Downsample the signal X by a reduction factor of Q. A lowpass antialiasing filter is applied to the signal prior to reducing the input sequence. By default, an order N Chebyshev type I filter is used. If N is not specified, the default is 8. If the optional argument ‘"fir"’ is given, an order N FIR filter is used, with a default order of 30 if N is not given. Note that Q must be an integer for this rate change method. Example: ## Generate a signal that starts away from zero, is slowly varying ## at the start and quickly varying at the end, decimate and plot. ## Since it starts away from zero, you will see the boundary ## effects of the antialiasing filter clearly. Next you will see ## how it follows the curve nicely in the slowly varying early ## part of the signal, but averages the curve in the quickly ## varying late part of the signal. t = 0:0.01:2; x = chirp (t, 2, .5, 10, "quadratic") + sin (2*pi*t*0.4); y = decimate (x, 4); stem (t(1:121) * 1000, x(1:121), "-g;Original;"); hold on; # original stem (t(1:4:121) * 1000, y(1:31), "-r;Decimated;"); hold off; # decimated 3.13.3 downsample ----------------- -- Function File: Y = downsample (X, N) -- Function File: Y = downsample (X, N, OFFSET) Downsample the signal, selecting every Nth element. If X is a matrix, downsample every column. For most signals you will want to use ‘decimate’ instead since it prefilters the high frequency components of the signal and avoids aliasing effects. If OFFSET is defined, select every Nth element starting at sample OFFSET. See also: decimate, interp, resample, upfirdn, upsample. 3.13.4 interp ------------- -- Function File: Y = interp (X, Q) -- Function File: Y = interp (X, Q, N) -- Function File: Y = interp (X, Q, N, WC) Upsample the signal x by a factor of q, using an order 2*q*n+1 FIR filter. Note that q must be an integer for this rate change method. n defaults to 4 and Wc defaults to 0.5. Example # Generate a signal. t=0:0.01:2; x=chirp(t,2,.5,10,'quadratic')+sin(2*pi*t*0.4); y = interp(x(1:4:length(x)),4,4,1); # interpolate a sub-sample stem(t(1:121)*1000,x(1:121),"-g;Original;"); hold on; stem(t(1:121)*1000,y(1:121),"-r;Interpolated;"); stem(t(1:4:121)*1000,x(1:4:121),"-b;Subsampled;"); hold off; See also: decimate, resample. 3.13.5 resample --------------- -- Function File: [Y, H] = resample (X, P, Q) -- Function File: Y = resample (X, P, Q, H) Change the sample rate of X by a factor of P/Q. This is performed using a polyphase algorithm. The impulse response H of the antialiasing filter is either specified or either designed with a Kaiser-windowed sinecard. Ref [1] J. G. Proakis and D. G. Manolakis, Digital Signal Processing: Principles, Algorithms, and Applications, 4th ed., Prentice Hall, 2007. Chap. 6 Ref [2] A. V. Oppenheim, R. W. Schafer and J. R. Buck, Discrete-time signal processing, Signal processing series, Prentice-Hall, 1999 3.13.6 upfirdn -------------- -- Loadable Function: Y = upfirdn (X, H, P, Q) Upsample, FIR filtering, and downsample. 3.13.7 upsample --------------- -- Function File: Y = upsample (X, N) -- Function File: Y = upsample (X, N, OFFSET) Upsample the signal, inserting N-1 zeros between every element. If X is a matrix, upsample every column. If OFFSET is specified, control the position of the inserted sample in the block of N zeros. See also: decimate, downsample, interp, resample, upfirdn.  File: signal.info, Node: Pulse Metrics, Next: Utility, Prev: Sample Rate Change, Up: Function Reference 3.14 Pulse Metrics ================== 3.14.1 statelevels ------------------ -- Function File: LEVELS = statelevels (A) -- Function File: LEVELS = statelevels (A, NBINS) -- Function File: LEVELS = statelevels (A, NBINS, METHOD) -- Function File: LEVELS = statelevels (A, NBINS, METHOD, BOUNDS) -- Function File: [LEVELS, HISTOGRAMS] = statelevels (...) -- Function File: [LEVELS, HISTOGRAMS, BINLEVELS] = statelevels (...) -- Function File: statelevels (...) Estimate state-level for bilevel waveform A using histogram method INPUTS: A Bylevel waveform NBINS Number of histogram bins (100 default) METHOD State-level estimation method ’mode’ (default) or ’mean’. BOUNDS 2 element vector for histogram lower and upper bounds. Values outside of this will be ignored. OUTPUTS: LEVELS Levels of high and low states HISTOGRAMS Histogram counts BINLEVELS Histogram bincenters If no outputs are provided, the signal and histogram will be plotted, and display the levels.  File: signal.info, Node: Utility, Prev: Pulse Metrics, Up: Function Reference 3.15 Utility ============ 3.15.1 buffer ------------- -- Function File: Y = buffer (X, N, P, OPT) -- Function File: [Y, Z, OPT] = buffer (...) Buffer a signal into a data frame. The arguments to ‘buffer’ are X The data to be buffered. N The number of rows in the produced data buffer. This is an positive integer value and must be supplied. P An integer less than N that specifies the under- or overlap between column in the data frame. The default value of P is 0. OPT In the case of an overlap, OPT can be either a vector of length P or the string ’nodelay’. If OPT is a vector, then the first P entries in Y will be filled with these values. If OPT is the string ’nodelay’, then the first value of Y corresponds to the first value of X. In the can of an underlap, OPT must be an integer between 0 and ‘-P’. The represents the initial underlap of the first column of Y. The default value for OPT the vector ‘zeros (1, P)’ in the case of an overlap, or 0 otherwise. In the case of a single output argument, Y will be padded with zeros to fill the missing values in the data frame. With two output arguments Z is the remaining data that has not been used in the current data frame. Likewise, the output OPT is the overlap, or underlap that might be used for a future call to ‘code’ to allow continuous buffering. 3.15.2 clustersegment --------------------- -- Function File: CLUSTERIDX = clustersegment (UNOS) Calculate boundary indexes of clusters of 1’s. The function calculates the initial index and end index of the sequences of 1’s in the rows of UNOS. The clusters are sought in the rows of the array UNOS. The result is returned in a cell array of size 1-by-NP, where NP is the number of rows in UNOS. Each element of the cell has two rows. The first row is the initial index of a sequence of 1’s and the second row is the end index of that sequence. If NP == 1 the output is a matrix with two rows. The function works by finding the indexes of jumps between consecutive values in the rows of UNOS. 3.15.3 fracshift ---------------- -- Function File: [Y, H] = fracshift (X, D) -- Function File: Y = fracshift (X, D, H) Shift the series X by a (possibly fractional) number of samples D. The interpolator H is either specified or either designed with a Kaiser-windowed sinecard. See also: circshift. 3.15.4 marcumq -------------- -- Function File: Q = marcumq (A, B) -- Function File: Q = marcumq (A, B, M) -- Function File: Q = marcumq (A, B, M, TOL) Compute the generalized Marcum Q function of order M with noncentrality parameter A and argument B. If the order M is omitted it defaults to 1. An optional relative tolerance TOL may be included, the default is ‘eps’. If the input arguments are commensurate vectors, this function will produce a table of values. This function computes Marcum’s Q function using the infinite Bessel series, truncated when the relative error is less than the specified tolerance. The accuracy is limited by that of the Bessel functions, so reducing the tolerance is probably not useful. Reference: Marcum, "Tables of Q Functions", Rand Corporation. Reference: R.T. Short, "Computation of Noncentral Chi-squared and Rice Random Variables", www.phaselockedsystems.com/publications 3.15.5 primitive ---------------- -- Function File: F = primitive (F, T, F0) Calculate the primitive of a function. The function approximates the primitive (indefinite integral) of the univariate function handle F with constant of integration F0. The output is the primitive evaluated at the points T. The vector T must be ordered and ascending. This function is a fancy way of calculating the cumulative sum, ‘F = cumsum (f(t).*diff (t)([1 1:end]))’. Example: f = @(t) sin (2 * pi * 3 * t); t = [0; sort(rand (100, 1))]; F = primitive (f, t, 0); t_true = linspace (0, 1, 1e3).'; F_true = (1 - cos (2 * pi * 3 * t_true)) / (2 * pi * 3); plot (t, F, 'o', t_true, F_true); See also: quadgk, cumsum. 3.15.6 sampled2continuous ------------------------- -- Function File: XT = sampled2continuous (XN, T, T) Calculate the x(t) reconstructed from samples x[n] sampled at a rate 1/T samples per unit time. t is all the instants of time when you need x(t) from x[n]; this time is relative to x[0] and not an absolute time. This function can be used to calculate sampling rate effects on aliasing, actual signal reconstruction from discrete samples. 3.15.7 schtrig -------------- -- V =: schtrig (X,LVL,RST=1) -- [V,RNG] =: schtrig (...) Implements a multisignal Schmitt trigger with levels LVL. The triger works along the first dimension of the 2-dimensional array X. It compares each column in X to the levels in LVL, when the value is higher ‘max (LVL)’ the output V is high (i.e. 1); when the value is below ‘min (LVL)’ the output is low (i.e. 0); and when the value is between the two levels the output retains its value. The threshold levels are passed in the array LVL. If this is a scalar, the thresholds are symmetric around 0, i.e. ‘[-lvl lvl]’. The second output argument stores the ranges in which the output is high, so the indexes RNG(1,I):RNG(2,I) point to the i-th segment of 1s in V. See ‘clustersegment’ for a detailed explanation. The function conserves the state of the trigger across calls (persistent variable). If the reset flag is active, i.e. ‘RST== true’, then the state of the trigger for all signals is set to the low state (i.e. 0). Example: x = [0 0.5 1 1.5 2 1.5 1.5 1.2 1 0 0].'; y = schtrig (x, [1.3 1.6]); disp ([x y]); 0.0 0 0.5 0 1.0 0 1.5 0 2.0 1 1.5 1 1.5 1 1.2 0 1.0 0 0.0 0 0.0 0 Run ‘demo schtrig’ to see further examples. See also: clustersegment. 3.15.8 upsamplefill ------------------- -- Function File: Y = upsamplefill (X, V) -- Function File: Y = upsamplefill (..., COPY) Upsamples a vector interleaving given values or copies of the vector elements. The values in the vector V are placed between the elements of X. If the optional argument COPY is TRUE then V should be a scalar and each value in X are repeat V times. Example: upsamplefill (eye (2), 2, true) ⇒ 1 0 1 0 1 0 0 1 0 1 0 1 upsamplefill (eye (2), [-1 -1 -1]) ⇒ 1 0 -1 -1 -1 -1 -1 -1 0 1 -1 -1 -1 -1 -1 -1 See also: upsample. 3.15.9 wkeep ------------ -- Function File: Y = wkeep (X, L) -- Function File: Y = wkeep (X, L, OPT) Extract the elements of X of size L from the center, the right or the left. 3.15.10 wrev ------------ -- Function File: Y = wrev (X) Reverse the order of the element of the vector X. See also: flipud, fliplr. 3.15.11 zerocrossing -------------------- -- Function File: X0 = zerocrossing (X, Y) Estimates the points at which a given waveform y=y(x) crosses the x-axis using linear interpolation. See also: fzero, roots.  Tag Table: Node: Top200 Node: Overview980 Node: Installing and loading1202 Node: Function Reference2312 Node: Signals2764 Node: Signal Measurement18367 Node: Correlation and Convolution23311 Node: Filtering30163 Node: Filter Analysis35283 Node: Filter Conversion47876 Node: IIR Filter Design58088 Ref: IIR Filter Design-Footnote-196181 Ref: IIR Filter Design-Footnote-296385 Ref: IIR Filter Design-Footnote-396652 Node: FIR Filter Design96871 Node: Transforms107654 Node: Power Spectrum Analysis120708 Node: Window Functions151062 Node: System Identification163225 Node: Sample Rate Change174077 Node: Pulse Metrics179382 Node: Utility180620  End Tag Table  Local Variables: coding: utf-8 End: signal-1.4.5/doc/signal.qch0000644000000000000000000043000014456505401013704 0ustar0000000000000000SQLite format 3@ #.c  o–«A $ § › 3 ½ ? É oX''qtableMetaDataTableMetaDataTableCREATE TABLE MetaDataTable(Name Text, Value BLOB )t ##/tableFolderTableFolderTableCREATE TABLE FolderTable(Id INTEGER PRIMARY KEY, Name Text, NamespaceID INTEGER )| ''7tableFileNameTableFileNameTable CREATE TABLE FileNameTable (FolderId INTEGER, Name TEXT, FileId INTEGER, Title TEXT )t ++tableFileFilterTableFileFilterTable CREATE TABLE FileFilterTable (FilterAttributeId INTEGER, FileId INTEGER )f '' tableFileDataTableFileDataTable CREATE TABLE FileDataTable (Id INTEGER PRIMARY KEY, Data BLOB ) 77#tableFileAttributeSetTableFileAttributeSetTable CREATE TABLE FileAttributeSetTable (Id INTEGER, FilterAttributeId INTEGER )33/tableContentsFilterTableContentsFilterTable CREATE TABLE ContentsFilterTable (FilterAttributeId INTEGER, ContentsId INTEGER ){''5tableContentsTableContentsTableCREATE TABLE ContentsTable (Id INTEGER PRIMARY KEY, NamespaceId INTEGER, Data BLOB )x--#tableIndexFilterTableIndexFilterTableCREATE TABLE IndexFilterTable (FilterAttributeId INTEGER, IndexId INTEGER ) !!‚ tableIndexTableIndexTableCREATE TABLE IndexTable (Id INTEGER PRIMARY KEY, Name TEXT, Identifier TEXT, NamespaceId INTEGER, FileId INTEGER, Anchor TEXT )h##tableFilterTableFilterTableCREATE TABLE FilterTable (NameId INTEGER, FilterAttributeId INTEGER )l++tableFilterNameTableFilterNameTableCREATE TABLE FilterNameTable (Id INTEGER PRIMARY KEY, Name TEXT ){55tableFilterAttributeTableFilterAttributeTableCREATE TABLE FilterAttributeTable (Id INTEGER PRIMARY KEY, Name TEXT )h)) tableNamespaceTableNamespaceTableCREATE TABLE NamespaceTable (Id INTEGER PRIMARY KEY,Name TEXT ) ää;octave.community.signal   ú#ú"  ßßü øsignal.htmlhOctave Signal - Signal Toolkit for GNU octave Manual(signal.html#Overview1 OverviewDsignal.html#Installing-and-loading02 Installing and loading6signal.html#Windows-install&2.1 Windows install,signal.html#Installing2.2 Installing&signal.html#Loading2.3 Loading<signal.html#Function-Reference(3 Function Reference&signal.html#Signals3.1 Signals$signal.html#buffer3.1.1 buffer"signal.html#chirp3.1.2 chirp(signal.html#cmorwavf3.1.3 cmorwavf"signal.html#diric3.1.4 diric(signal.html#gauspuls3.1.5 gauspuls*signal.html#gmonopuls3.1.6 gmonopuls&signal.html#mexihat3.1.7 mexihat(signal.html#meyeraux3.1.8 meyeraux$signal.html#morlet3.1.9 morlet(signal.html#pulstran3.1.10 pulstran(signal.html#rectpuls3.1.11 rectpuls(signal.html#sawtooth3.1.12 sawtooth(signal.html#shanwavf3.1.13 shanwavf*signal.html#shiftdata 3.1.14 shiftdata:signal.html#sigmoid_005ftrain(3.1.15 sigmoid_train(signal.html#specgram3.1.16 specgram$signal.html#square3.1.17 square&signal.html#tripuls3.1.18 tripuls&signal.html#udecode3.1.19 udecode&signal.html#uencode3.1.20 uencode.signal.html#unshiftdata$3.1.21 unshiftdatasignal.html#vco3.1.22 vco<signal.html#Signal-Measurement,3.2 Signal Measurement*signal.html#findpeaks3.2.1 findpeaks*signal.html#peak2peak3.2.2 peak2peak(signal.html#peak2rms3.2.3 peak2rmssignal.html#rms3.2.4 rms signal.html#rssq3.2.5 rssqNsignal.html#Correlation-and-Convolution>3.3 Correlation and Convolution"signal.html#cconv3.3.1 cconv&signal.html#convmtx3.3.2 convmtx"signal.html#wconv3.3.3 wconv"signal.html#xcorr3.3.4 xcorr$signal.html#xcorr23.3.5 xcorr2 signal.html#xcov3.3.6 xcov*sign   „û®„‚'„Rßxœ½‘Anƒ0E÷œb¤¨›„¤dY5÷°ñ€­™ICZ%géYz² %U©”]–FÏßó[‡1ö¬i5†Kd/*mE%kIY‚tđ,æÀY‡IgàV°'P´ª%Ag5sêÄa¾đ3¥ƠÖ0Ë—+¾N7₫†[ç!ÑŸœ‚ ½™ùÍKáüưÅY¹«Ư1J̃Á̃_A•¨r¼8h™ÊÔ$ñ› ×—̀‘Ư—rÄF xnû¢̀^²u¶1l·oék>4JôƒỊ´ Nq!Lîä}æƠwæ»₫ Ú_’Áº! e* 5tl::j́†ơ₫ßjeäëʺ†y½Çæú'́;ƒö ‡́Htxœ́½ë–ÛÆÑ(úOÑ[^ŸCZ$‡¤4²%y´öH¶b}Ë–µ5JœDGö „h'ÉYçÎSœ×زŸäÔ¥»Ñ .¼ÔŒ"%–fH º»ººn]—oÿÇw?¿x÷÷7ß‹I2ơŸYßÊ₫G»-^D®¸,ÅŸ_ÿE¼s¯½`¯;ƯN¿Ï'³øÉÉÉb±èŒƒy'ŒÆ'q8Jvä$ǘ‰h·¦k;đÏÔMlz­í₫1÷®Îî½ƒÄ ’ö»å̀½'†üÛÙ=x99Áy<ÉÅnr6OFíoîŒÄK|÷ÙÏĂľrÅ…7l_´ƠïÂĐ¿ô1 #qH}{Â/Yr=uÏî9n<Œ¼Yâ…1ôV€ï=Ë@¼t—‹0râÀEnΣ¡ÛN²ØqÂá| ?­<îxqyƒùÊ‚Æ~8°ư•gÿ́nd'ad<8µ/]ܲ•G¯đ‚Û¸̃x’<]wúoËñ®:îµ=ÁxÿœÚÑØ Ú¾;‚¯túø@<³ƒ'“&'*G¦Ÿ}^H¢0wwÔF,‹·í‘=ơ|xl!€Âdèó…œ̀ ôùQ́Ư¸O„sq£[s¿Óºlæ¾ï&âŸ>B›đC´óDm ÿmÑQ<¡ÏÎå–À'ñÄuÑY|ÊM‰‰l;ŒaØÚ>ĐÖ·ƒĐYÂ4‚ñÙ=7 ïŒ?ßâÄĐ·ă †3ÀÙ•ë·4¯đ½ư“ñçÍç¥-Ï˽•s/?†éôẾÙ‹p¶ŒWâÿâƯẠ̈ñ7Qø»;LÄw8pæF±€5̀è7n4ơâ@x±Gv€/ aĐ˰à –©ÀMvcD2צv0‡ù̀¢đÊsđu{¨'„ œ aÑÓ³tH₫JÇ„—Ư¨̃†Ïmß—ct6˜*µ:Ơièx#¾‡9ă+¹ÉÎè•g8^BÏC²̀E.½`Ü2×e'ô ́ s†)ÏưËĂ¹¼ÄÙ¥3qŒ‘XMĶ̣H€*0\ÍÎă®ËOàëØ·“¢•{¼dè˜ïÜ»­t–=€³¼‚–mĂG€ª©¹÷lv9(4åy@`‘ûL̉p-—£3%ŸRL4º9MÀ ¿xÉH 9.́€ö•íù¨ˆ0>%Å*´æ‰È2‰ˆ•ø¼; }ŸÏư0œN‘´0đæ¤ZĂîȉ 9·â}â³ \ß…­ƠƵă”_³p‰Áá™]xP$ÈC+ÓIÏéÏ((^ ˜ôFẫè‰ G̃€è帕Åë"4ñúQpÊÈl÷:;§PÏ;ă›}NÀû."ÿâGÍ“7¤ư3L¶ä­;¶#´ÖXm+˜,“ĐÁß¼Tû"M€u†">DF {§²«e™´¡ø¹ÜÅtLjQÀ‡jĂêà;®K&íÚĂÉÆâ"vIw*̉ÛÈê—cí·îÈÜ`èVÈéüĂ(£ơ¹ĐŸo.Ÿ‹& eóª&VN£̀ ăb5Ÿ ù‚́“¿nN²z&YsVóAùÄó¬æơ0ÿÍfĂOÁdn6UÎÅWoŒ¼(Fx„fß ¸oD}™~œƒÔî,´zơ®Ï‡0.¼tï™̃̃—ÀŸ°9áQ~áÙ·ĂĐq!Ø»ñ́Û+[1üxïỤ̀Ûø÷™8ûößx&¾e£Ù|mç{Ï2ø{xpuü½ ¦2yM`G¹Á®y°–È}”~3+ư&œ%ü]SÎ=Ư¢Œs@Z×ú"‹Ú?=_Î́È~»¥pwâ$Å›s-h‰S§]µ_ễ¯÷eV€›ơ˜úp}₫rₘ=ƯiTíƒó ˜ószPØÊb»R8vbƒ:sîBÏOf̉øsº.^¾¹J¦ècàTùpæ¤Ừ̀pX› ™ơ½âÁ‡ É’ß$PÓ¬:MJçt=rqØ “¶Ïwƒq2±Jç²£ư(p¿Œâ?æáÓ(,}ù[G¼*Xl:8n½±Å60úTÉr$¡ØÂ=ñ ¶OÉ¥²ƒÚ& !PC›ặ̀KË̀lƯẩË —o¯œ•tEn< 'f×Ơúwå¡5|jŸ¹ÍD—ëöY!;=x»xȬvÓ.?WĘº#—ü‘ĵ&h½_ÏJiƯ´NK” ,¥+ÍŸô®U,Ç‘\°œ7 cÑè•KhÅư-u’‹ïPz<[yXOŸ•ñƠ³(Đ,0œ'³y¢ù|ÁLV xf;$`Kđ €p¬Ù–ñØÇT]Ä€ÈđO¡Û2„L™øUÔ¹SÛ#— Kd‰hÂaÂæ+:©ä˜°³s í 1×;ù£wé²YŒp%Ö?çhSt—[ÊQFtƒÎ“9ÚQh© Pü[‰O”Àè¬ §̀Ăy,¬ØØṼƠ"»¶J;N¼hV­œƒ!„m®›K˜û«æí•]5½2ÅK.hưz'}X®§Vu˜aîa½GÜcÔƯ}ơZ scâc¢¯à«¤·;f+íƒ1ûđ“ĂlÑ[{ ưá~úŸ„ô‚¯â‰=swß’ÓlÉ£Ï[¢¶¤H¯um {TíØ@Íî{Ô<ç ~Ñ;ÊĂ·ÿ̃Ô-X¦Ộ…8ϾAÆà(rÿ˜»Ápi‰xáÎđ ô[W,́+­Nnèí(²‘Së'Gª´«@ »1!S±/‚¯¶23€¿F@rÖïÁbøáF|XR‘@$Céưq=”Q”¢‰1Đîfs3-˜>GŒ¦#Àι3KÀi*c ”É_ư5’¦8Q¯=ê6¿j$'I¯)î‹Q×|ñ¹í`̀Ơ0}·đÅ_û¹WưplG`ûLÓ—ÓWOàƠ_å˜_á‹koœ£̀âésO¼QBx=ëƒ/æäµNơ5ñé8 ç΅¯½"/Ớ-Ñ`̣m  ù¹ !!signal.csssignal.css> #gsignal.htmlOctave Signal - Signal Toolkit for GNU octave ÷÷ doc îî!qchVersion1.0¼ï>évºỮ“ÓÍ&à́ mEóFH2‡=ë¶aûa÷Á†#â² €µûZïôCK<́v[@3øüơ%à51v‰~…1N[<4çÔ;ù¦Ûí>A(}|¹ß§)s¿LKàó̀¼ë2n¼^Ä2œk£ÓGKø™ÈO0]â–·è/s;]° øVáM€ă%Đͽ} —™‘%¾ƠÀ1t‰̣ÓƯÙ‚œ†°½Qµù@¨ç¶°#5äLI kkrÓ{ƒÝ•JºëÍoR„í!âưAéTæå_•ßÊ_ w’àzcÖ̃N¼§³¹”€ø³ï^‹ŸÂDQî¿{»C/̣†Ơ”üPĐC›“±„¹?  ú x‹J‰‰î)ËHp;b’Ú’è ‘ Hư+ çßî=»pAôăđIºtĐ₫†-1¶çñlц±½HÂ0™́M‘ d5Qê¡7§Ẹ̈₫¤©`Ư*êLQrlG_ZMI ö6+Ô‰åÚ¤J©Ăl@íÑ· ¾,öÚ›ơñ2«­ö?Ă[±Ÿ†Îܧ$.à¹ó8ô x`àƯá(Ó±àæHYơ;pxcđ[ƒ”™Ë'‘‡?́Ïä1Af=—$ôƒ[°ùv |^»]Œ>ÅJ G .”¢j-¿u“yÄw¢ă”Îùuwoêº×̃ÄNªiëk!Ûœ²4ÜưéJ‚ºCÖ™ÆÖÇ2ζ£Fà­tăŸà- àÀ«́ºL¬©»>¿®&Ço„znzTë H†u«ø\’ư-®mÉG¡cKú×åxßó=;Z®XZû™ÿƠ¤ôXđS[’„Z¤»ÄÖ$ªîW“èƯ(ëu)½pM„{W+›Óa zJT°nCKQrÓÅ)7j`™êËƯbªS|Öjaj°·ÉÄÿhÛ4Û…)¤(<̀ÎÜ&ÛÿcïLÁ7/ă½6­̃ $ v8¤ÿ¤M+øÓ÷ÚÓÊ'ÏĐ gçH‹åY<Ÿ6U7’ûN«Óé4›BKY‚NG`ؾC–˜ÚIä]SÈÄ"”áÛ2ñC×Uî‡́R„¼ĐYíx©µ̣ú“¼d{c·èQ’ư•TfB-»c‰¾kG₫²E:nήU^±˜xđ°=º³$Îd2Ï @œKFd1Đë:2€˜–¤ ©{<æJ.fa$û~õèï×)F±8½^·J7ơv4đ`† Ë³ÓMàæYbÔŧº]øBºåà9/È>·€Çè¶₫©ñ̃ADôÄÔ‘¬öÄÏü0 EO¢—ô£øI·Ók ú¹Ë?ó¼̣Ïño-±hÂnÄ+7̃êjsk]ÛáđwVªaƒ·ö”˳„¯¤‡‘nëS?£e„“¼ŒEC0ôÄ70ªÎdŸ…́²\ÉÜ& Q0…σ™Í¤ÄÔ ₫R|5Ńe¬̉Ơ)Å£Ú)Tp3vl‚0Ù‡TI&Ë9džqäEK 扑êmE¾Ëd̀µ8'Faï” ™È6!Å Èq^í¨Ñër(JIâ>BùĂÍ6Ĺ `”n·÷0@¹¯1@zÚo½¹’‚̃ßQ°n•’¢äØW„):jUx4ØÛd?Ô‰å e§[¨QÛÜBá[X^ɇ)0‡ i‰â­W ¶¼Ïç£Éôó— ú«fËÚâKè¤Ôýæ¾NL9pA^QªyÊü1Ô'Ƽ<*/zP$Ë€Ṇ̃âíø÷Nq‡Đ,×ͱñ'½®DÖƠ²ƒ¡«“ yµ–(aæææüK™®Q¸ƯecH’^;ÖuÙ¨BSÖÈ‹¾aÙ\^¤ ÷— Ö­’)J-/RtÔ*/4ØÛ$/êÄr‘¼@n°×l.3ĐÂS¯‘Ë™X+0YP 4‡í*O÷½)Öơ)xø~ï¤ƯÓ¬\Û†®ï²ÍX”¼œ€¨Àç:D.5Y.A±Ë‚Ùtu½‡ pi=½*2€uÍ‹-¡äç>àW07q#ö%Líko:ŸÂR( \¾÷@¨·¾t ̉WºCW—)Â>åxùtcv—¿€×ôBÖtûI9EXJa =?úÉmZ¯ƒ¢%°ct8O¨(2¯:̃†ˆ5–ö bo§ÛtCơê˜níJæ­Å|ѽŒ7ƯoWÖk”áG•MJg†* "(Í€ÅSº|ÆÙ"@|G²K í<Đ«ÙŸóxăiè9¿u»§#̣¬á@§B½AOoÁ…̣ƠÀVƒ+) ,Ÿ4»Å1É"ñ Ưc”ßHF» Î<Æ·Jg_èPZiƯuë -£èiôsn̉€éÎGÅRó.–•Eß‘Z~‚:–øßÂE¡Åg>kÁ’†]jg¸qËˉÚ¾¢¼đüSÉY·Ó3Í5눕?{*ŸåJeEăV.ªáµ`¾ô{Í‰Ô ‘w^…Eœɺ~vÙK®ÙÔ ¨—¥¥¼X•]© ¼À/ñḳJ+ÛÜ?¼•N° ưË—³îX¡Ÿ¯µok§e·Ó$ ]ïÊs‚„Sk…ˆÆeuơ’Ó̀eφát@”¤è‹è˜îM fI²2¶¡‹í©5…¥dÏVk<N§E{úwØ20ÎEă¢™³ßÎ }; W¹¸6Ëăpêª́u]Cy»ºWÂjzߢG&Ÿ¯‘8t–úÂFƒ®AÆHX‡¨ •®́Ø¡ÈéªêURØ=tÔc «®ĐÙt½‡AăJjµ…´¥¨8 †PZë£c¸Đ[=4öÚ€zkli°(³uÛ7 ¨v+¿Ükƒê­¸¥ÁîQtkS“ê¢Ü½WúÍÂw¡‡ƯâÙS¤m¬i“†3£R<êJ†o–Ñ¥ŒEKËi 'álFjhZª˜ê uíØë«,©z–Ó4Y¤‰ó[i—¡XÜB Cä`́ÓĐ|Nˆud̃/_¾““Uq}´Åº< Đ?}Äq¨ùưSć]¹Ưµèơ/¾3וWü’öé›÷×ø2ˆ=ç2´6›úÍ ~Ă_fÀ’EÅøé,́+]¨ ăÂæGÅ]€4̣®§Y¼T!æ4‹ àa³_ˆ‡…x’^È£g‡Ÿ‰‰7`£.ø’9YŸ×}Ñ#`¸r¹° øîbk7.ư'øüWa–'đÎÆÊÔœ¡’‹ă¿»_úÉÓ₫u†‹n:ÔÅÉÔ¾`ô¶I“ŸœVbÊ"æö5ƯÔ çy ‰à`Dó¯öĂ. !~‡̀C–Ëá‹́;^ ßy _QïpÊöưSq±6_BøóĂqăB¿¢z5zØ4lÓË„á&¢1Ú*Boéx‘Îăy­’¶R ÷ưỌ́O²!LJHæá'éeu₫ÈÛ6 ‘Ø`ë%™ÎDd„í”÷b7dŸ£PMC<6£´ #pXŒ]Ô< K†öh‹¦aà ÑYl{>†/ø.&Âv„̣@¾aÙ#Ó8ƠƠÉQ§áRHèK‚Â9b¡zö#êú™CW±¡F7:…Ÿ}ĐSAшQƯ‡.56E&èÀï±7€‘¦b˜^à‰&½ª¡c1ä@RHO±à‹’çM*ˆ…¾3“0̣n° ¨ÏÄ æjp¡øNÆÑPHˆkt“á ÷[:H~‡2¶[pđ¤ê9RăƒÈÅn1̉%œî'§OȘj)›ó!¶¼)6Ÿ¥Q¦è¸Ë“,넱NªĐ›O¨Á¤'cÔTmx!I`©/iY0à̀e¹*ñ«÷ ^4“±™g®}™ƯO Y¥£h¿×¤²zÿxÙ” ³›^™*ˆ/ÔsĂĐá b¦åtsAWQ»hn&ÄHÂÁ=À®ÇŒœî"}Ë*ÂÖí†̉¥ ) ñk;̀WaáG™ơ K̉Â|ªó[(Üg-6‘§‘­£ơN£Ø/…©Å2V“c¨§2.h%I<72éÍ îóÎ7o‚A€*ÆÉ1HT‰*ÎZ‹¸‡²êŸÁC/Öí{%”Æ 7²x=K›K_M€öKM³íHơ…äˆrƯ₫£’<À"WE‡yG!-ˆ%¬ÀT2)H/v‘Ï]xu™XÊùđÀƒí*%!èÇb䇨yO n( ₫…‹†LØqke²±ó LPÓ0%. wPCÀăe_*c¥"™V2¸#̃,À8G(1FWp’àăïÏ@Î̀‚µM=Ÿ’ÿ,¹ƒ’Ả9Ï®Y?î=CónÁxIÄ™T‘mĸ:¸} ƒ?p›xÉî !¦qªRè®c„Ăßd.Ÿ Qeî*J¼N!åW©đ¯—̀±Ưlúâ±<±ưQ̃Øe£Ù js gơ'€> ƒø!ǼI®‡ÈÄLHU)LÆÔ¼{eÂR©: ă$O¤¬´đ‘OÜÖÁ(N2Ê„xVfT}}@=ḉ…–à’›Ẹ̈÷–> Ct!EØ€g€D‡8‹#)•Ië9c̣8ûé»Kïç ;̀Ưl úwP(î$¾’`)©̀Y}ϲ%Ư Œ₫­±ΰƒÉJĐ‘¿—x¤kéN ÎxÈË+$đ0 ®FH£jç(U'0Ùœâ`¤;»Ăª´Ô¤GÀ\æNƒêlêđïs-úÇDÖKѯ?¶Å•¨[Ă…(A:BB‰rưmàà•È8L%€y²ÜÉ//ñT¯W>Ïäc 'ün•yÈﬦô1:ßL¡œêèø”*eă=eDCX±-…>µa@Fs°xđ(›ĐaÀÿ*¿¾1Q'$ïlô‹DË$¸zª…ǻóÛát¾BïÙû¸1\a‰vîU â>̀ƒ'-ú-sô†¡Qç¹…ƠHëËÑ“pÖđ̉oÔx›3S xn*AƯªü®Â7•Îc!ŸÛ\ÓÑ€÷×t$¨#h:á<ÙXhŒ&]i§¨R©Z%±‚zx5èöá¿à›«}v¦^IA=¼t—v¦$Jr䇋"‰5–×jQ¯¼Pă¦ä37Í0Bg!@Ø)gÏ|uFÏpÖôïªñ¶`ô p ŒAƯ6F¯0r›½ÂT½́DB½eŒ₫(ø¯Ñ+dgn£ÿÈ;Sd){ăÀƯ©\®FñZ.ÿ¿æv`4ˆ¼ûTæ$•¬¥DǼ̣onîÿZ¶XñgÑAl<̃Il°̀Ú_l–˜è÷̀ộ-ÄGPk™ Ü‘ MlMÁÏa V(?FI†-ÏF°aq ÙN ë́‚¡̃#Úc¥øÀ–k«\p5 ×r_À3›“0ÜŸt̀’ƯŒJ—"­ï 9NưêF;Ñ¡¥Va«Uœ[ˆè<ïM+Áhj«ÚMµîÄúKÓ(Hu¼8´‡œa<ô|Ÿ¿À>ÜFÚOZma°,+ ×Â.`;ăIÁ”®Ñ¸EرôYÎơIơwÊ‘×Ñe{0÷eG#ßË+Gjm9O£Ns̉AZ톻ô:â<-pŸM];ˆÓœ•–èá<Œ\NLj Óùơa²¤k7Íß ú_•¾̉±`¸†¢u¨‡`!/@cÁ¸É4ʲê½X¿wa†RU¾³™È—z3e“I”ÎŒV¾^ïÈaNæ>ßÿL¨ÜkK—zx™ƯĂTkdÊI” œ¹S*t.jû'×ç] z°̣fÙĂ(tú‚¿Æ7 ¦l&¦¦ ¥Ö†’s€(.¹J~ö;=¡Ü\ˆ°÷¥ØQêç]–'ïúa¹8¤›kN÷'¬|nÏû ŒÖ*‹S¸µ;T"î¡p«à©áºÿTœO‘‹‚a¿}¨×Á­ƯÅp¼}à‹·ïÂ9 ïÂs\G&íˆáơ€— bNƠ(¬à¦O[ª…¼á§±ßÉ,Œ=º'f¯|F Æoqâ’#(â4(Ư˜+ăĐÛ1®‘̃¡œ…%½Éêûf5¬#!%‚"ém©¸c[?Đ©Zrî5†Đr8ơƠAw†¯RH-YĂ([DIßÖsŒ´LOƒ– »à/ƒpêne ¢†%WD7%]mÂƠ¤1‰ fÎK5‹HX„íO’$â Ü8ÂG<ñc¹Đ}¦³Ö ¼’̃†ü,™ĂÀ]¬]2 96vô¥,&N$“|&Ogk0ä®ëÖ̃ó£ÁJ&gÀL‹cè¸àCE#6³ÓΓŸÅôW¼¬wJ9&&Æ2Ă5££́Ă·c±ÂÍgĐ(¦[w)ÛfV2³á¤Sæ¿Jïñ=êÍ`79€?yræÊ(è'™€D‘4r¨ÉbÖ€5;âgLá5“íë^)if‚I`<[Ê3¤("¾ÎÜ_æD¥²Îƒ÷Å̉9!áŒpR"ø0á̉Œá)—rgñJi…r‘xùNÆÈT`&v‘ h>*¦¡W‡ý"vX₫ɇÉè·„y2³38 Çf‡r.Ba¨ÄâkÆ³ÜÆËCÄ ±B Jö¢–Qaä`R¥æA*#EnR®dRhÊTÀQÈüÇb… âûSŒ:¦}‚eLÑ…!ëHƒ0P̣‹,S¢ öeD_‚XvëzƠÛó ζbot#-Éă öåƯÄè·eˆƯØ28'__ØE’'Y]¼ª̀H›eđ)áj®8Ö>ËÅ”éè±g¶øJ4H[\w›¿ö1L1 Œ°=cia«Xz–LÁĐ¾̣’¥^>®ë.q$¼¹w¯7G¼}]‰x™2¸ñ«̉WÁ¨úæN~–³ƒ~g'¹̉¦d7À’«¸T P®¡¾́êBC@F ›ÑÏ•̉¸9*GtÂđàԣ൬Ué4 ‚0ÛÍ‚`½“x1p^é´Q­Xj±œNay²¥aj°Q‚ùè®›­c¹wj¡U{LúB?¸E{êv ư©°[•O``åØu. „ÔÛWĂ½MYµ"º¾âë²¶j·àx£H3¦Wæ˜SÖf0ü,5ƯL ̃¼ex»K(Đ½¯S;Ù– q[TÇ¢`Zºm­́x‹Sbẹ̀© ú˜è»jR˼mÖü@«(¯M–ÖOk qX̃®†ÄAIƒ’èw¹–”¶—-æ`Ñ J₫+ÿ¨‡}¸jîù@½%ó$È5ñN€uûX'¡ä£pNBGưŒÁ̃:¾Y–kf›„ª­¸&oJăSvŒÅ Vô1]›.LÚ¨{µURjăíOͬ̉VVĐ¼fJbAW i'af × ¸«•g¯w™»â_u²×µœơ¡Ø©ÖÄOo+ư(\´~zÛxç­c›;p̀6(¹à¶üï](/6.øQkç¾í°´‚«0±¼ÔÿzûN4z'¯ÅÅ_~úÍ+tĂk₫Úof›§ï̀Âsk.Đ­;É·]L̉£ˆŸ?2qŒ¿Çóì`UsïSo öMkàßçv1pBĂÑ98¡¡^ o¯ ³52qBÑö\e;IF̣̀íÅ>Œ|Z½¼V¸ 3?6#_Yó§Éˉw“gà»Æ¾À Nwl–Ú/ÂàJ–2­¬x‹£ă²€ŒG6¬œƯvñƒC¬¥V%³tz‚Ú\hI˜ûK-t±5ܘ¹JĹÁ]íR™îv\W"¯VaÇ0/ínƠ†́‚öí¤ÅV‡í×bèECª̣2LOtE-”UÔt` ¾ŒT/fêqñăFó?9¥¦TF–9è—MæÖ)l¤3Áê¦XoQ[Ư ĂsśV⬖B)ídQºåMq_”=¢ö^´…jÜà@9#Ư°cFbœ Å!p;úâ”5ZbưR_•¢;0Ÿô[¢÷äa“ª¼}GÑS!zđóCøïkø¯×…¿¾).Ù~¸ù´DeJp.?Ô<Π¦†Ú08^‹N2åÇímT"¼ir]-£ûB>¶…”VpkÓ ê]ơ²Âáw¬jµëkOTđERÜ¥.™BVy]ú¼µQ¨„È* ’ç‘r5»`M|U:]UêK ̀e‚eà)7¶ׯ—ªŸñ`»PàpÛ¬mÅ­À1XÆ%1ÆÊŒ,°¸‚e*O#W_óâ®̀*?)7ƒ  ÄNï–]³0½¿#;¦¸5]°\PÇ>ÄƠÄ”ÚmPR„Í äÓuQéh_‰=(l•Œ4» ·̃Nî s6î· ¹Ô´fwÜV6i'ió½̀’¦ufd{˜^G#“ŸÆsâío×ËÆ%]®* R·ï-ez…Fæß•˜Ú“˜¬O­ĐpJ™J­4ÏË'áʼ®³ó*å–́+¥k¾YÇâ2íæ¥l̉{KÎÉaê×Í:ü53¬fKß´·¨E. ă-µåđ’ØơGÜ››Ú…˜Đ¦Â"³×¹MQ¥‚è•¢,ex)?i`v¹4ó_7 Y°tùĐ¥|H]Ùb`íjăÏkK“Ü̃ßëß₫éƯ¿ü7j¯¿7–¿yX–>ưăơÊZŒrjå"™—¢at7×v¯ÙËÆëû½fW‰=7;âuÈ'ÂâPO9¥̣hg¬P¾xê›v ‰üĂ”£Öf$̉a®6µ̣Nà!ØÄ!¶Jqs¹e2 ÀU®¿v‰{₫öÏùéû×ï.vÓbÿV Å¾Ç,Zw:K–O)GíÙqûiÎ4ø@è_Í‚+;øÙqV€K؈ÅnTóXÊy`î/¦—2Œf…1S²b@|r‰~̉^2´̀Lx́§œ»¢ºØ7OS6™Y¯²º .’Ë0¬”âYËœF™ ưAçÛ˜CĂ«̣>Í)1fơ~íu»×’yÿ¯µçUµ UêÄ_Óà7¥R£`»[²X†jʽÿ¼‚’£Ñ×Y,' …‡¸P8a^0₫ Å̀h•Æ7 lÜÙ̀÷°2€nçb[Ÿ†>?Í Ă!<©:º_ú1°é§ßb©5Íàç{Ïà¸bÉWøùÙ—?dÎ? ñÁ‚ ¸HÇœRK¼m­˜ÜåC < ig³ÁøYƠq†9y½ù@ó`›¡ÔÓÆ` ]N¯ÛÿºüWsóQ©br¤´́fÈ í÷ÀE7¢iÜ€mÆ–Í&Ư#ă1ÊÉ^Ṇ· ñưzå[à•̀bưQVM¿ƒ4µ½ˆÇªZ”Ôà0ªÎêÊ0cYiWzYüÄ^S¼(W2«Xq%Ç+1©™¦úK£ßç+bÏÊ ƠĐSÛÁ₫ ¹V×êû[ú5PĂJ ŸœFgT¢P¤îOú¡Æ+-^üº5Œ‹ÂĐ£8±dơê¦k'0ܤ₫W¼Ó÷{,Æpùo~íKp±do0:`«'6|¤I½ơ~Gµ[5˜5¶BY"Íâ÷*fSu#ü÷¾ZTëÍW tđû¿ƒÂ&ç°z¹§L’K\Ëê  †ô•£=Y„´®Æßàs°&đŸß›Í¼J‡¹ä^nÀü[O­7­7ê5´Ü‘t„+(€ø7‚”{»{E4ö$!„ô«½Ç§Œ¶₫–îă~m₫ă₫!‚HÔö!ÙÁÓ?„§·¿«÷đhª+˜R­ơÜĂ…[æ<́oP*Ñ AíWÀÖ€ógơÜ(À³̉†¤¢µI£ï®t¯ÄYÉæ¼ÛiUFj 5Êɶ0>Di_¤C»Ø’ '•&£´‹ÜJ̣"V¼á`!U u­Mª©¥Z¶hH‹ ™!‡×¡LY=²° ª]à"c™°¾(˜ú`™)ö‘Ú́®ïNơíp î­êøfO…\Éz!ª±$S ÆiÉA Ç–øx•ʪÜ`ÍÙƠ‚LöÜVRƠä ôK©@H<¥ø™E¡3yá7ưVuׯª•(ªœ–OÉ¢Éz­^qjq@bE:âßwEïƒÖwe!C ^̀O·Ë̀hzºàfûđ¬~‹Æ€ˆÔ¡U­‰Ûz$Ø›»…FUKÔ¹[×ñ[EƠx_wlüÈwñơà²Î«ø5ñT»aù#_Äo‡åCƯĂ_Ơ ơ±oákẮ>zôƠwđJ‹†§mlÓ=¤^Îøs8¥;ï̀kkª¯Đ¸n¶–üÓ²ÙüĐ©Ôà6º´3“¼Öy%‹.ă¼Q ®å»^œrưT¿ƒÂM¯…»éµ(©íú̃[ÔWz‡…îçt^Xf½D¬^äÜDælđQơXp¿÷$h÷>¬-Dry’›Æ¶72kï.Ftë©Pt:dÍ—#àm`iëû-GÉܬî#®¹ËÊXdéƯ“¶Ñú«ˆ·Fí|cÉ:ÉîºpK̀ü9ºv­Ôp420€Q́ê,RcwÍ|I!¸V箟á¬ö‡B°y»1ζoüÿ«RºRĂ~n›~7 rínÖ­ÊHQ²‡‹¯Æ8.¾•u’Èi£kß ¶jcWq0ä‡nL…›íDr] È8¥kÇ †¡‡˜a¼7”uơp’j̃²kE;¹Ñ>áûâüØT]® E'¶ñ(¿Ü_ªyÁ—31€÷sIʹßûƽÀD?œ æđ{ÔxĐƯN¯ùTä₫|!NÅ7Â&̃-‘ˆ3Ñ}̉ít{OznÁ‹úư*1óJÄơÝ₫W3ï«ä«~çAó~·Ó?ư ز4°"|#iâT¾Xº‡Ççqè9÷ƒĐCD.alEAËn]Ăă7̣CXúè ̣ă-ơœg~˜4’ÖuëOO1¤ééŸZIk ¿(XôÁüÀ₫)[₫%e໺'®7¬æ•}ÁOmÇ)j=|̉K̃Œ¶b“ˆ#3Éå®LñWsç)zøä²;³)uÊ4Ä́z‰vᢿØK°1̣2Ï CÉ%Å›ªäÏƯä÷7#n)¤óù¦€°‹pî;Ô8À ŒREá4mD sÈ+pà„ˇÄâä 7]Å̉2¯BT2?³T!²–ÀÑÅ.pzÙd‘¼B~¼kÙJĂ%wƠnå܉µ<Ñc^ï}Oq½ƯÛoN§ƒ?ƒæ‡–đµ,í1h¶{̀Àß/éù¥~~ lz̃NŸ·›íLè©üøºù%°kŒ™Đ(üe1`Èq‰é£K~Ô.{T‡]:“¬·²±%–\›âƠê¾Çæ‚2¸iÆ€̃M1«ˆpjcѼ0}°WrbU3j‰ëư'µ2lÁ÷uĂO]g̉«–t„znsY—B̃_Ú)Xµ4•̃ĂH±p:;•ƠHqS«,Ó`«¥Ù'‚̣–x_Ô\zÇÂ)î³%ƠÎû[¹% 6 đûÚ~ưÛH{/‹ºbÂ`'ÿ~­ơJĂ9d³¦±S¥ëxváƠØ$;pÂ7Ä*ºWu¸’Đ̉ư~Ê)’Kc©À^̀ëhɘÄîGsßïX/‹2¸Ô8g¢?½ß+×Á[”ë)µ®¥Ù>ñîO› Ú Uë  e¬äqÉf̉vG» c¤à•ôP,˜vĂưÔxRï ?̉£–₫¨²đæˆ5=Óq®ZAÂy„»/Iº#Dăê§i™4½qF®óTüd'¾=Đ¡èT•ĂTæË%Ù|8´@SÓN³¼V]öˆ¨Ä‚Œ́ ́@̃âJ/úsÇ5k¾[À>hc¬x­´4Œ)15ÜÔ MÚqB­̉đÀXn>g„ê·Ơ±~V—-‚(˜_ Oă0ªïªmP|^Që/ĂA`¡p§L4d5̉Ïx̀XujƠeÖE­kTÚH‡ËQ>øK*¶(‰ÀV€çª÷5K˜ơ´ Ÿv(Ư³­<°Ä±¨[©ÔÿT¼bz %dRBóẴ“²R€ÊĐ«svµ\0)·'”0at¤Å—`®¡D2ø|*æ3ê{†\¹ŒkítO Ü—Rô÷|á–okV<́<úÁ-”îv Z·vŒhFÉÄÜw‹Í£a œƠ /–Í$ÿE4,ûæ¥́ë|ÖÛRI±¿₫.]5Ơ•4#°L¦ {̣ ³ K«çc]ư;$S+Ro< =G±„»C–!L–̀Ÿ€$Î?¦ĐÇuătO`˜ý¦}I•|ñ¹§£Ù„Ổ E×5¥êDîs7.ÓVº¥{#ßer½Î„©‰´_DÎE½ z“<—{/ÂY‘îü˜ÄïoIß›ăÄăĐ·—ë/ÿNEúäæ<Ç„¾?ÓI¡Ưª+@1Çî¾`¢¤Vƒ̉|xŸơÇÂu‘U¹ç.ÔkÖ€kÊ»»P—̀Dă¡ö§öؾ;½?Eá˜{î\eØà>;wúyç6Ú¹‚o’xÏM==Ô¦>ú¼©mSjS¿₫OÚÔÊâÈZk^LĂP^ “'̀ kåɾ°¯ÀĐº\¶ÿŒEL’íÄò“Ÿ…₫2§ƠràĂ9ÅdÑ %:₫óå8y*f!/•¿ª%fg8-8›ƯïSøáúZgh]‚­Tg;ªP]cË6+°_ɽƋpv´À˜R °cKÅVSTZÇÈ,JSÔ¡plvf¢ÀÆaè §pÁc™ÜØ¿‚2àÑ¥ÁSäÅo&̃xb˜£ñso<öƯ¸#̃09tG²Å©À’eY"ô‹Ê 8 ¶Ñ#í‡ #ÚK4†ó$DïäA“î”Z€¯-qÚạ̈&ŒÎ̃P—iNÛSØuhùí68˜ l^ƒhœ¶h®O-A¡ äÙkôZ=œe¯ûUHÅ_»đ«ñƯ‡§#&ẹ́¦È̉(ÑÓôó§üQ CTu4G&8€ §Íœ ^Û+ ă§jÔ6Tƒâ›ÿôưáÓ‚ +q­̃¸?€W¼±‡®{ă;û÷×`„́ïKăơ„GB>¶…AÁ­Á…À Öø~ m9¬P"åđ̉DádQ0ê¬̉ÈZ/I86”iZ]¼zơV²ätw| ȯXÄ’¼‹Z ÆĂÈ0·æÔgJđ-ÇÉ2Ũ(ÇD=7ä鬓d:Ëgß&ü‡´Áïó Ÿ÷$äÜ7çê›ß" ă$Á„¶|gÆ:£ëC« PƠü^—ÎïuÙüNxùø"Ĭ¹IS àĐƒ®ôÄ ÿAÑ;eRoäÜ̉6ü?…"ÂR$<ØM†’^`4âú†< Óé"̣µ‚û¥r´Ï /c/^›Đ¡Ÿä´S™Ö!ÔÇÛ&w#oŸâáF˜d^ÅOe’?¹]đ²‚^O3C;‚Ÿ÷Ç­Âeb2»}ø«BVíËđá=À·òlu¯=ª×?l>¼ø6îQ¿Èú{n̉aa™B?m|‹J£TôTt©·8²rZ…‹†P¾e×ÛÊ襣å(´´ƒü»¥ÈéˆWd£®¯ºaáŨ6{tP•æ%/¦‰#‡5TBSƠAHo` J₫Ï…†Ñ ‡î,‰Yû0B.CJkƯ±it΄üS¢NÑ„L·—­±•¦Đ{æ̉Z-W9!ÛN¨Üz$*€:‚8 ¶b„Û%K Mµ3i„zx)z\äkf7$o°c¦ƒ+¿#Y‡¥+ç†k˜¯µƒÖÁ}-d¿Ä{Ó+—.´eËÈ₫mǵß"Ù ñ~dî «uFn§äƯ"ÎM¬i" #°̀Éæ§–1qdµw±Ó)gäƠËH ælô“Áë¼ÓTPăö̀·׸hĐ¹ô24.ơƠ‰ç¸yrÑÉÀđçÊöÏ[¿ơK³s¢~?çß©ÉËĐö}Ơ%e*¥ƒâk°Sê_ª¬zd¯œˆwĂ4—n>o~O¾6`·RÿĂSaó=¼$X`‚¢ht[âaKôúß»C,+¯ưbÅǾ7Ăû­Û=!6ª9ßCÆoøä–́Ï¡&>¨!¢˜°¹Î=á¢ô¨Mv>jƺ×zÁß S#Œ3]¡pyĐÊz.ML‘¾-&k<|§ŸÙ‚ b dp M·H'4́Ao»U 4Ô+äá­‹#b¶<*bwœ×́yC‡÷¹çiy?¾HÆ›y¥¼=nëª$‡§<nÁtܵơ†=ÈĂ<µ6‰@8‘›}»3˨7:‘@>.ñx¸‰ûÊ Â¬‰3síKʆns¦‘m”ü‘®̃xùË?5ÑåŒÅ²î*C³£zàđ¶¥ŸẺj7¾’₫ö”–?Øq›êµœ5ØÚ­ç;¶M¹STÿÎƠ›¼§ÁÖºw7øßNw¼)̉³ßüg¢Ñ¡˜Ư7‡Ù¦Çơ_´îƒÑ‘óx«™”-(èM§å „Ôr?n‰Æ(©ª¥¡b&±ºx}™F8ä ë(ßi“L@µư95KÄi¯/́`Œ ™:[Q«̃=]N©bæuÄ"Óx{¥6B2 è¡Íi{Ô}Z;b·bŒ¡@O66–¦âK.v!À÷©´Đz₫ 0!ÆO¼™¿Äeđ›®}4s#/tDæ¥;*–Ă|ŒZâf%æ[v%î%æ¹s¤í›A& ÂâLD êÚÙM¡Ûó²Đ;a¯™Z+¨œ\fsƒ¢­•®¹‘'.6̉Å5'O΅÷ȦMöj¶Omß7ºṂï³È›ºñÚ ·d đü3-BM6¿ |)= ́ÏvT0́Ëx¿Q^Æ'ươ£,®†‘×!u±~üB4"ËGRIQyđë7Úh!æ8#Ñ€₫ĂZĆt: ĂṆ€®€0u W&?~5RU?“jÀ$¦8»0d̉l­Â§'±«Áªœif-³YÚÉëü8Ñn`!°ˆ£¹f!v6ÅÂù˜ ¬0Z‚ÜÀS/k³!sC/úº£Ë 85£æé;êạ̈Ľ%ÆEv íœ8 ñdƠ?h¸¿₫¾h₫ûCK¨̉²ÄÀÉljÉ@œUwË,w•¥́5©îëĂϲh̉8ßöïLôG-Éüc‰Ơ?úµL8Î׬i?4np.Ï៓s₫9Oƒß.Åͯ—ÍüÅ–¿ṭSyÎÍj3Í}·U+ éÍŒ‰m₫‡>À¯4̣$¾orèÍÿÉ#¼`H[ôÅ|'^2O8uF’¸{E ¨¶0—E]z®ïÔLPâ\8ÏqưÂ9_¥'sÅđ«óüŸtÎOÎ ×z.ç—ö:”MkÚD¹gLÉ’¶.R}t¹²uç«OÚÆ“çKf øs‚Iï{ù.e„†ú u$OÅáG0ç”›S¸>ÖuF1>K¼©wĂùœF£kàºÇEk5’V*H²P&éjùÚ(~O@Çö£üö;ÀjÂÉbíCÎÁqA…ôăV´Ä$IfONN†CÀn'Ńđ́t\g~̣ÿÆ'²6ÉÉkÔ¯¼¡íÿö"•¿ưyéoß!/íL’©¿oÈ¡7ƯTß}-đ™Íïâ₫÷DçwDåájÉæÖ.£èØ÷CŒ¢Z Xy„{¡[…ơºî„yơïÇî‚îÈ~ÔucÄh­§pStçwªÈ»·“1^ÿ&îqŸT¾wóÛñ́×Ç̃ưÙ \2±à…¹»mí8ƒ m‚âñPƠêV<̣td+ÇŒBF½8†V’È$”©KÚ‰¤#qĐ³ŒŒú¼»ÈæÔ$[ơö4Z^c§Q‹)%¾×Á'ƒ‚'N¦ă6‚·¬TÓáÄâ!FIơ Eè¡:$³×ñÀ@₫Üîơ»Îs‚¿qèühww‰XÈ<cOƬ±/æ–$hmÓœiH˜$˜¯‰%PfÁáE…*ˆPS‡¬•fò]LUâ l¢d·fđ¦%nØ„ß[©ŒmßÇZƠå7B?¸…z™Â®AÇTÀnU­+·H·IQU/ÇƠpoS¡z¶`Ç${%ëyùwªó ·dmæê˜Phrp1ơÆ*½åpJ»µ¦ĐÉ>©öù°N­&„X“Ê{تååF¹ơµăêÎA•‰§}ñSO)#ơüF‰¨z³ Óë9^uo“å¼%₫ˆ©ưß°È/a¨§âëµÄE¶_ «³e‰śó©´J:.r‰†8ĂkÜQn>‹́†ºÅ ±7ÜfÄIK<́6úÿçÿù4[¢ßư~ê÷°2æăÇ;́”ˆŸœœ8¡× £ñI¯Ûéu{Nà¿ÓvïÑ76w»¾i_‘¸°²₫ñWÛs–6́¬¡%̃tđÿ?¡‹†”Œ‹%ª)÷8•ÔÛÁ%̃ơbœÜữsí(†₫"ô}ẃï¼+̃₫y¼xj_“¹Z =é“ÛH¤z"IA»e2)ÈmJ)²j–JđíKµ́ÂÎr)EÊ¡°}›*¡í†í –‹›™è©K!P)$|­ÖP¿¢a8Fdû6f$T© {k Ö•y6P¬ôº°7° ´ơÊ·-Åg¯ ñÉØà›…dÊè¶̉øÊ9Od s˜ÝÁ¼`ÂÙ₫¡Êeˆ‡đ?©¢°UúI“ôELøA¹¶̣ólæ×›¶Ä¹bwí-Zñ¸«x„₫€ï¼xö©Û~‡Ư¿r:ĐƒÈÉIxÔ?ºëê^°TïuEúèVb]ƒ¯E¬Kh·M¬kÄÜ*±®‘U· Q€o™X¯cvë)‡Âö-ë;`û b]£§6±Î™Ÿ,Öÿc¬ưT|_m'¾7–̃Ö‘Ä·ô4t;§*Gƒt3(bYëg¸ ’;Öơû+ävO¨·‘Ú t2›aAb¿üñüÏ[00…•=„ÅóR‘}¾3S¸Z2₫V÷úöĂ1¸È‚s|¢đ ½{û—ï[̣Ä`n<Y%–ñ~N¸fP8]‘¤×VEơFå̉¹ÁAÉê‘©˜l ¹Ôœj+Û…½.bÅÁ?_q¡¯X™ ûv®‰ÑKÜ)v´ÚÑe{0÷}—êÉù^AĐñºQg¯è€œ "@ç Đw9¾Ô/¿Øđv:K–F ~2÷™ëüL{·ÏSÚ"Êh£•%rÚX™äÊñlY¤vƠ°«NáT’£ƯˆeăgÄ×â1jx(ñW#ßĂ·êl(Î~ÓÍsñ¿‘í;ă÷7-1k‰K³&́#¬âđuKü [Wư©I“9 OǛúøCC¾Ô,?'¦̃6 ô1l·pgv½ÁgèÊ|4ü¡Ú„Ââ!¶æ% nơÖ¼ŒwÚ‹zËH {%¨i;¡eM“ßƠBđ́ư1‹¿—ô+r=̣‚Åê%ñJ f©ÎPl ÛêËÈ]q®Äk® “©l†Q<™b猧Ưư¼[€3-‚¢övbó­ú—Åyù¾¹ËBƯßeÁṆ̃A­i½û¦TÉ™í¢«µÖªhH {xˆÀM}µÖÍûdp<Ü\$ó¤ut*çPơÔÈ$/pdKÊ׉zS¥’̀ÔÂUy§P ˆç[ÎZébS<ó´^s¤M©>ñtÓYI×{ÙA ü1͓ё·K2pJđ èMĐKđHó–¬pÛ¦GJ<˜#› éÓ,cIøSfN ÉÆ|q z–~€2Óùê„uá̀uµ PYæ‘îÂR M£0LbƯsZ"¯µJ¢X(|IwFzN6L~8œGÔåÜÂ9ÎZ¶E§‹QÍT|\ ḥaûf¡$Y}/¿u nT¥ÜŸR} `2gáSµ=´ïcÏî›_í^îÓÏ}ü¹Óéà'?Ñ'?5-³ŒÂúj Å¥Îy\ǵqíܸökúäuÓZ­U“Ö7¢-nÿïăÛüËOÍ́›8e^Ëư×Í5Ó_Ó^s¦Æœ™cÎ^goƠ åf¥IơCÅ‹ÇTCMYbé‘2’Öôµâ‚k£*J›ÙĐ{yífϦé/¨BLͺ¶éé³Ü8ư‘ ûO¿Øºuº9₫vÍÓzÀK*[¼>êô„znsU-…¼¿²¦`ă†)Z§{mUoº¹S*EñíQ|RÄoUëL=†I° JÑ"E2ÙÁ²Ü´drØđ×§ê ½ÄÓóJƒ\₫v₫Ó›¿¿ØÓTBQX?Q G,71r–i‹JWÂ2&JèqAu±—̉±Pa8|8œ¹\€k#}éSeÁ̀,€Măqtç‘ä½Yí$5]*‘$ç*«îâ<’àZ {;÷®VJú"ạ̊[*%µ½(Xÿ JÉ­ ¼H_—R¢Ơ‘|O›b sk%ßgÁ÷Yđ]đƯÜ-Áwsk_Æưêº0:?µ¹ĐSP÷y é¯<†²\˜ K¿q6x ¹ÇRÈƯ@¨QÉM8̃½G à¾î¶cl¿Ó­ O`ÜOFµĐv2ª¦í‡‚ŸÚ¶j=´ŒAÛkƠ¡MéơqèUëm¢z„xä[‡ư‚™Œ÷Ø—ơ—”›̣Ü­MÚ»³:§—Ú™̃X>¥Ư)`ézP®́\¬¹r&yrỹ“L*Ȇ̉ß=Å{’§ÉT¯+̃Öß}XÉÑEÏójWƠü`úƒ.^y úJ̉·2Û]¼§²û “ÀRè½–p“aºå6 `÷«¿LzXxßÇ(=|Ñ×™_9âÁà)ö2ÆCï0¯2đ̃ɈÂH¨ÅOY¯p ÁÛ%,ü îª6[TPP<ŸÍÂCúp"—Fh¡E“›(̃ÁĐŸS{¥3†9•h¿›™RY:v¼PÛFR,¾¤.Knó*sñt¸[©1NCÎ`B@1bh 6‰êđAû3QA‰¼E1{–ËB•Y(’…=̣ÅŸ\¾¾¨—%Mß&wÆƯ–©ÇØ”§—ĂËå°¦eƯ&¸Ø~8ÔNf1³1£1W´O.q'lNg+UÓwŔ’¦³µdZ[‹”®¸̉¯ofµè{7³j}ïTđSÛé{µ}ïfv }om4WÁ7—Ûé"ˆÂ£ " k×è4Á;´/uꈈÜÚtD ’±D¥Œ$G#ăk~V?«»«¨9ZŸUÇ;¥:î¦ Ö¤ î̀[nôyf—{;ïÄG pˆjƒ"+q…¨Ï5·¸f(Ëa))Øó5`/5Ø̀Öœ•â¹ñ*5K. öÍ0**°˜ ,ÖƒÜÿiw;ßổ]₫¤Ûyøø2~GÑSq#Îdp"ÆPö<ưKÛüå¾èæ‘f Œö¸ÛÍ>œÿé| ŸCŸH¨—Øoj¥œĂ–*·©jK[©à5ªÜë=¬Ø›»…Â]›ơXîƠ`>-¿pƒ-¸½}|¹ÅØRă[ï¬5>º EáÔ¼<(ô®¤%Êj¨ô–à·bªl]ÉUöóî¨0æk8œç×p’ŸÏƠGKøè~ôƯ¼,dyµs™_á¡f₫JmÄ™Hî?Ăïg¥=û€zñùÂ%íÅ5ÖÙé_‹xK3½6+ưS1̉÷¶o/Ygî›Æ#ª2B–cÈôY7Qá F.ÊÓ¼3ï̉ĐDYËï¡Géª:¶–̃ÖZíÎG‚¥sơ™øFÊđÍ…‚ºÿ©`HÇ8x 6!…ªÛD¦PX«ïJ­ƯwUåx¸»¸ßÜ •·³æ/Å•»O¤À—¬ô¶¬oè,([†ơ‘cöî§nPᩳ×zêAÅÛú»ä©ëmਤ»X’Zb †®Âå)‘‹ívÔk ™¡›Xi“tê-Ç~4×i*Söđ~¥ è–½m<Ù-ûñ×qlơ-L½ çapè£9èm)b~Âù˜¶gK}³6uóÓú”˜ƯCEÚÈë´½´y‰ïú₫ïKNñƒ·Jủ©k“s kéç ´5„˜ëâW@j̀¤a—{ëÚ>‰Mx¶Ạ̊Q}5ä|*ñ¨ çF†;îxÙ©^Ke‡~û‡»¾è½H.öá·”ÈGi| k uŸ’¿NYw›blö~²i]œ9Ơöß*Đ\­E6Ư±@s‰©;"k¶'c‚ùñ‰äĐÅ‘ÖwDÜ(iÓÜ\Üʰ\;*8ÇâóuT¾~ơê­ª>ư‹Ub+*_çåÊ×_S=[Yư¿Ø¼̣uÁøÛU¾¸q́úvåMå×̀Qäç6çd)äư™™‚u”K år>bKí’/Ñ0̃œƯ¥Ưçörî•bsĂ>Ür÷U)åù‹Â$D,w‘p̣Ư`¨)ăg²*t̃¥7sÏî„Ñø;yN€´.±¢=è€ûZŒ<ƠJ¹üu§/W´…`Öpë¢æ»SdKăjB-oX¸ ×]~KA=ÂƯáƯÙƠlÛï̉kS#ơ [u„ëÄ]´Ê-®wØÄƯn´4ʲGèüѼ`Gߢz{+¨ơ7 V«<0 ºÙ‡ÿT6û%eçÏnàRË[°^"5z9wV¤0§í™O®rx`Ñ+ơœ̉ỹZÜ&‘Çn-ñËĂ&ưpÁ­¥E÷/ĂyFbæ}ơËPD`¼€ U PÂñŒÄ–ùG?Øv„›Ö¬56Çèt: -bP‚²Ù’¥º̉mº2û_e®Ïdm4ZÜVzŸ<|e.-¹Â›̀JƠällÖE­"Ơ–üCm  J'r€±óD{Æ`vkжœ‚ÅKè™pZ©ñ¾‰Bû(åK{:{*~²ƒĐ§ß½ÇûMllÉÙQù––âµ»£Ë'¼7œz¾Ó}3ø^Ú‘wăÆFw]ºiÔùT;‡÷‰û+=GW_óù}KüK¤ÿüKüĂ×™<«‰7¿°úù¿üù¡qÑÔOÊ_ÏÄEûÚ„ ¿8ë4à›¦†PÇ*øOˆ¿Gc!óy"ưû×ï'~₫1>o§Ké*.DûËq̣T´±±+=Œ̀+÷°₫|ø¿̉i¼7÷yÈùđI|hPC(ü¼T亾üB)2®ă…s »ƒÈN9ăb{C.Ă<¯ø:}îÛ.64VˆK ̃xÉg·‰è¯ˆ÷[¤i 'îđR0u§)K?Ç !c÷ƒ%ï¬5¬C>p—aà°HÑô‹Ñ´đ`̣̀@zr„x.‹²†£̀ÔdmUAQ³¼Ç ¯=E4ă©j‘¶RÉÈ>Ă q$p-º]["*¤<ºÉ$tb*‰¹ô\ßáÆ¤2„I"#y)'Åè Á¹M«oçb$ë.¨ ~j ?…„Zƒ—‚ ƯÖdÚm,"‰Â£ßGK®µ8Ä]¨äß”×ÑÏáu7Z/™ä±ï̀œqàœÀkbb#ß̉©Ôä4¼÷́§ów??‡añ‹gœHxÈü“%uƒ ïÊöhX%$ hJ­ơm[Où´ă¬O{§N<\-Í]ă<•ƒmwĐÜzÜéî\›KDærv¸ëIsk÷ơ1Đ;si~Œm)jDK¬é7\Û[W³G~—è[oê®<‰°ĆÂ'}ƒ~Üư©ù₫œ~äëó1X¢il…Đí.Ï ²́ zé}mÖY'/­µË¸‚á¢<iƠÙ-¯º9Ÿ4¿ˆv×Ë\W+ln‘è+c›#–áÇdáºlpq5É0påûhí×íqƠ$iñÉ"l»ÜCægŹ/-P$^S|éƒơ¿hôWtDåÑd+’”·̀ -È44ÿ !¶ÊMĂ¾Ô³E¹Àü„BÅ lT·Ë^‰“p–y\ºŸ”\6^ák/CÄ)%y«e¬‡ḿ¬‘å?’I²hFóe:¬•‹\™…ô Ø"fŒbÉ£´zŒ~¬7)“âCÔX̣́́ëÔ{?ˉâ+¤U$£arμª"W>êd b óÓ®Ü^™éóưGÉ́Uûí2zÄg&GXáû_|XæäCÙª"÷w ç»».-5·)XéÛ}C6sÚ{™œˆ>6Wªu¥̉E­­©è¨GûEq4ys ̀r¬ƯÛ{î†Â“›üªRº–¢x¬½gf·ĐtgcÄ̃Ygj9ƠNGB>¶—‡àÖăæPơûyẾø µoÂÇ^ƒE¹¥»(/X•¿íÔ®R£·v ¡Öî:î¦åMæÅ¬W¾m³¾4[åzqÅ›qúæñ¶¼~çB­Ư{ôyË‹¶|o3öê pÏU•Ëơ·Ùv¨- dwOáæ ¯ßµÆ‹¿Œoñv¬wd¡¦5O8vôwo:×ƯV¸¨¥¹ç}\iµ[´Ñ#ŒS‹Üx1¬g#1äcä¿z/ˆ4æ°¹JêÈ „ŒÖ%=”¾Sªf‚ÏÚTñ-!^ʧ<*2a` èȾw“Vùz½üc«0ÊÈÆ®xßmơ>¤R'B©Él¸ ˜ ½ªÈ›Í0&̉µăyÄ₫;P0p}ÙU¹”9ª0S¹a":ïÜ΄….Å-]kFAÏzÔV ”‚ W ŸÙúeu‡®ÛưrUD;f·Q\yç¬]„â/hXTÎnj_ʰGƠ'C¦0Î|8Ièä!º7‡X,/ \6uç¥CŹ¡Öa¥%ÇÈ8Ѫ齔¸ù@‘ó/¦ªv…†YMé’]P–AóƠc©˜guøđH§/Ăé(\Gú¶%Æ`&íî KÂØË*¾›qÎ0p̣ùx¿µrƒÜó_?4~i₫ë×>ö:y߻߸åä—aó×Fÿug½î¯öÛ“^· Rˆâ›c,-— nCÿ “5¦s?±7œÇ>÷¨ÿeH‹yÍ(që-G¥₫2k½uÄÛpΰ¯•V¸×‰ædxtÇèƯD‰…#E.0₫á܇où¤ºk-rÔ†’ƒy¥Âmµ$¦N„”Ñ-èăfIÄ ‡»¢MLMù^èDæ¥Î1̃j®2ÚÔE=t®ÈeeDƯñéhdÖÍ~|“y¬#ÎG¼Ø/C«đơ=¼Daäé~ʸS\[•ª4­…Q»ƒ=ÿÔ§ŸˆÜá§½=™²Úù5 »¹“!îïÀD8ûx/ËŒ%^ÍAâ–®wq+ñ:7¬!Ä╯ÓeœxLdàiOÜ+ă¦D“.åIû'„³-®9#­è%6œX £ÙDoÁ±à°̣ê[‚=$ÛÀ×ñŸk?˜2rư/’SØ| Oø8ä¿̀FIÿ¾7‘/NøMz“]²%zëP×,ƠX]’•Ùr1>×₫˜ƒ!‡)p­ Qø¸êÚDw,– g3†ŸµœÖ̃º(îo„|l»3Û«'[‚ú¹5Â+̃îÔSDcwÇ(ïô´S¤Ë«ÛêëZöªB½KXs8Ϥ“ºöđ±î[Ơ. ¬[uK˜¢äî_¦®Ơ­Á̃¦‹Â]öí®\í¸ëơ^j°·é®đS̃ơ½. ÓƯ: |äëÂ-ơ¨£\O¥¸9 Ê?•û°#uƯ–(°úÚĐR÷†׆ÜZ™kĂ#ÜZæ­á>—†ùæ¢+w†ơ^Z+w†wùÊPÉú-¯ Ùbø|eøùÊpư Đç+ĂÏW†Ÿ¯ ?_–]nw;¤/…–½ƒ]ơ×vµè ùÜv>¬~}₫æ₫'ăoîÎß¼³'£_£¿ùv9œûÛ9œµD^ăp&lLĂưn:A¬½:ḶJëákÚ½æC[rƒ=ÚưÛèÑîBí₫a<ÚưÛèÑ̃vßîosÇ]¯ß£Ư¿íOu×÷öh÷ăÑîßö¶Ômidwjÿ0>í₫mđi—‹®íR’>ÂʧưÙ©ưÙ©}+œÚưÏNíÏNíÏNíÏNíÏNíÏNí£;µÓœ‡e¿f§ö²·ÆƠêVw'‚­Ç…µ́Ư™½ QñZW˜´;u¼U¸­Ư– µ{®>Í Û·®Âö!¶đ%|ï̉ø¦ụ̈íÈùï´ơ»”èJŸ₫vTưÛeƒëw_Đ#8¯pé»ƯÖïî´B„b}Â%·¼?±?_Ô’Û»cpïË \û6%·+ƒ‹Ë]ÎsêT”ơ;fÚXsIUVT};Û³•u1ÀzÛY’¹E¸ºIUAU[*aK†$ªƯv½<æb•Åt×k”~•#߆>ƯéTT›î¸¤Mwq Ú_ kÍ·èÎ.{÷Ưvt©Ê´>ŸGÑœj´~óµQ£•;¨ ÊÔgưïpˆ_€å,%„‹0ˆ[âU0¬ÇÂﯱđåẫÊÂï×fá÷ï–…ß?”zZu¸³‰ß?„‰ß¿[&₫GܱZlü₫!lü₫Ư²ñ¿‡G³ñû‡°ñûwËÆ¿­ÛY‹ß?„ßÿTlü­¶~²¿ÿéÛøÇÛŸØøưÛ`ăï„Áưmü₫~6₫:#?ÎùúB߈*³ôûdÑÆơYúÀZúz”CYú¹fé÷o¥ß?¢¥ßÿd-}â!k ư‡:°¹/îoæ ;cåK,ûV¸ÊÜ©DÄz­B–ãëÿöîä¾~¹ØÛ»â¸}{û¾~Ü’ló]ñÜÑm̃× 7é÷½[“ÄnFªD×¶àSv!usêu 0̀ë?Ø}{¹äÊ«½VÆ}¤Ö`æ½°ç½{¹M[úÈ´¦y©;tr̀Đä+ô9pä8a‹wß?|ü ¼¨ ÛÈwBD”rw88x`{°ùyùæmKô»Ữ üµ¥ BßÚª;§B>·¥c£ª;Ô'PuGcñ Ũk+È£¿cA•ü ^‡‡æ³cƯ÷R”Ö\æXϱ^_@ç‘ÎtỤ́`×T@GÁºUtR”Üư:)‚ëWăo[]öí®”RÙq×༼mt>å]ßßି€{gJÂïB!{xLÖ–ÏÙ¼XK˰>\Ăbës•–CViáƯạ̀,ÖơYä·̉>̃¬¼tx™:éç‚$yEísAéü\äsA’ 6>$Y=X[$ÑîÆ'âG{jG-ñ“ ç±ø+¬dèÍ…~;ô’đó½gƠCñđô‘h[â…¼$ŒÅ9aÀ¯^æÈ³oa-URŒâß{;+F^4›®ñT|-è©ÍƯè₫> ´ÆAñch;¤i(µwG³g°±Ù#±q?âh]PÁvZ±D`­Vìö>|¢›̣?ó:*˜/ƒƯ·¦^/ìv|¢[óÏê½s^•ÿ̃e›êµăfµ¶)½›ÏËëƯOD½AA ³:(èn£~̃Ươ1̀ê ;…îæåđp8́á̉à(»c¿̃†Yá³#ö· $3Á¾̃ÜK¸ó₫́‚̣Ê0 Q₫Í­By‘WÛƯ¢æùQ·ă›5îÚ ̀˜‚CÚ3"MK_“K l};jÏ&v ;ñê­©ÁÂJÄI(z̉¾’‡1&‹2_úG#q-£jÄ0̣Đñ̉Ï8u“IèˆÚ£? _ø€t&'`ÜủƠŒÂ0 B°6ißưüâeO¢ç̃/₫ùÙ<óÙ3¬§3ŸÑzbƒåχ´̀+0g°æk˜ yBaú45ïÆµÈZ·¯ÉZ_¸̃xV¸p£ưn²pƯÀôds€×0™Û¾áỖípd¥.XåÖ^æßØ „…»¼Dx€BŒa Dj!̉Z —7Àaơ º4ä—趘”̉Ç›fôÅ.̀«)_Q–ơäBîĵqC·ç)¡êÁ”}€ô‘Ú¦ R)[¤yI£è›Pæ.á—‰‹ÙI¸ _0ă ̀ÜÔƠŔ–gŒKK#µ‘ïΆwƒ¥5‹Ü+/œÇ>P»üÖÆb×#Ç=µ— öÄKđJ}28ó餴 p,Z[P°¨s1 c/AC÷!†ÁÁ #’º¢È ´₫¨>ûF)äĐ…£̀§Ú^0„¨.x₫̃¡•™EêL²8UOøÀ _5ÁË‹øÎµ‡2üѳ˜xX:\r]™{ki÷bu4ˆ÷~OD=á÷EÔ×"ÿøØ…]i?È»“¶é!óGT†AgÀç…µđpä¡—ÀÉ‘´¹cd9–:¤ˆ£y{ßV1{"@ë1ooy³)(¼hN€~¼ÀÀוíÏ]í#®G©”ˆäå¸ €D»á÷ÂnDô·ß§ŸáoP<øVæU|«'́,̉_1U`-¬<¼‰¦ÍaªzÂ^l9.é”Đ6‡À‘hEÆd¥¼º —+'#Yù(½Øta{²w›aÅÓ¡ădFу€¹uº„–²/°IKzáf6¸qU:©WTÜ¿̣¼afx’e¥ïØAâ¿gâđkhH’ÑBö ‰y P¨ö¥§Ÿ¾C·<̀(́¶E6†ƒRë8ß<ƒ’̃·KĐ!Æ̀G‡eÆaÉF¹¶€Úhéè}dCåȢ؄ Đ´¦Ûd˜åïJú'z•§œÄĐ³•-e)Ü+ J̀êâÅ÷Œ½¢Zï¤O/HŸ^>½ÈëÓ+ªøûEO,Ôi«PNY ™C›ªÓV¥:}Nñ60Väú|vØ+‘¶ô\ß‘1@ndeŸKµăê][w´Ñ̃5l |d+u¬„"3€·‘r'Q8OHfT º^K6øÄ ³ œ'æÔhó# è#@ÆßÊÛçm‚¶$̃%‰ )R@†y€t—Ú-“‹oÏÀ¸ZÙ{χ³”d̃à©Ä 9©Åƒ³ú«µÍ¬oDÑ#‰‡¥~²ÓÊSZ;Ĉ₫€SÁÄ€:ØĐCs‹ó³Ç]4FóˆëPºDC&̉?i¦`¤g̉ImÄÍΦ 0{Q@p™1?\Ẽ –‚A.bÊäøO 8¥Kºˆ 5M09˜\˜w(O#[nèÇD~-—¬‹‘7$-íCuyèÅ 6uˆÅTÄG1>+ua«ü7›2XnÂf2åcYÚG'gÛ‚ô†$k¿ôƯÿŸ½7mnÛȆ¿ăWtÍÔdH¤HÊ‹lSlK±&±́²”ñÇ'’ „8hI¾÷¾¿ư=Koظ‚²‰*‘)8è>Ư}öåé>FÅÊ¢æËq† ,FNe*e &¾ÉnL ç£Äg.=aN(;̀Ă1 t`² 1‰ÇYơ!KÔ }ï¥Tă[AĐc³‡¦uhD)̀)ƒyfƠ‚cnC‰ï.ü§˜F5‡d;]–À¦̣aË1¼H‚±–¿Y²ÈÓk ®ªµ1¿óSTĂ₫ôƒü ́Ëçá²C˜zŒă^:O­¶đ {DŒï"©Ăám;À9i#qœvxëVÇA: ½[ª£ø>XĂK’£Đ3₫ NË È«Ê²,ŸÆ8©È ’Ø‘Œ9ôT%ôÄS_F8>¥ëâ¨2 Y$ >“sl<§£9…Í4¦cJLFQÊSötăĨgê »ç D̀TZMtÊñVÿa%+–¡¼¥»Oùîïû"‰¯;R‚3¿Ú†"Ùơæ–‹9_nTèṿ†„wßœC±‰ñưn;ˆÄDÚCLEœÈ¿ U2˜ÔP¶|^?‹‹:^>zí,‹6ó¬ ýe” -›—B–!M\`æ_̣Bm¶ï`(ê-́a5û„N#̉;†ñ₫eá̉„gK iÆ£+dñZÀ?<‚t₫FE]z“zëdĂx|ûĂß2˜Y†œqœ]>ûSđ—?UI&4́%ƯËÆö3{đ̀¡‚­£+±N×î2˜=x¿³â ƸơCxYoÿ_ÿ]×Ù¢Wåeÿ à¿Z}Bÿ¦Â§¹Á›è¸¬‚72ø+wj#H ü›lá«OĐCÈÎ.ØÇ(Hø̃z%*SR¬‰l0˜É²ÁØIFÛ hÏ~ÀÓ†̀95r®äÍ ·V7Ö¤‡¼&1 @L¦lxú#o•L±“K©í‘ÔZPR@±[]ÿfÎÑ”||lü¾ /1ÅÊWU8… r!00!HƠ%oJ̃Bă@z cu0BD(Öè/¨MèVÚ0aq>+-&#ûñÉè0ºôGW,[çܲ j‘uÁüS éÄC*z»ÄÄ̃Ô'–jüÖ· \c!‹¥®Œ?‹ŸUÎiZ6ư„½úüÄ9NÅ3ñøa¯×{*#ø|œî ?‹3:¥¬@eK‹9p¢ë á~2‹Öƒ+>ô0´¿¿đ÷}üưQ́\¸Ö½í§9ă¸6‘79ăs̉@ÿaR˜ØĂÜïÓ0{Ưđÿ#₫sø³¯k·I­[æ·̃ÁpOP)6gI´ŒMíµvnøƒ5üÇ4îÿÓ܉{Ѧº9¤¾µZ˜?ól̉´ÛƯ=†||Aßï·Û÷ßoßÅŸë,$̃‚lˆ±²Dáˆ=qè‚æÏÓ¼ÏÓÜ÷ÅCq ú½{}₫vQ»zÔ³¥á@%UÔkÏ#m"Xæ}¬1+Ó=”µËÖç±?eK _â33kÍ‘a aV¬ÿ”‡öĂd& "YMẒÑW®x3ÊPôA H)/—„ªÄûLĐAưÏ>{ZĐ[Z̀0”bÓÓx¦h/BBHá4ª\¤èT‰êÀpØ̀†â%otù69›Å̉½ZLÆGOÑàääꯀrï]±Â•ư7ª|¢VÜ–ă_Ư$£hyù“avÙZyE •?Q°î¢²Q½Ùù8gË2~ê­Ơ+sn[QeiVR}QÅ bB›¯™¢Á.ÎZúc±·\́ªÍs¯¢¢Áđ-,‹€hËߤ؉AênÖªñb'ßôZƠ°Æ–qY•M"̣‰Ëª˜ü£ăºe)$ËJ¥¾:ù¤Úé—]ÑÁ…ï<̣ÄuĐçÈ'«EûOu^æ\5¢gµiLy3qÑ­̃‚±7hÛa'§o3íÔ„¤ª˜¥V Â:Ùp{5\zˆÊ© ‡öÇ •!×FS×Dúî0†‹Ë#¨E!„:°aê +êúÈT&ƯwDCaËb͸åz\—àRû3ëª<¦¸Ÿr¶ÆA ˜$ñ”•"…c…Úª ̃f—ṣos¸‡z!Ûp+7{‹ỡ[°>m̉SWeD…¿'q^v¹ÌÁºê˜p2…·ư;uO-?QƯØYB\•£´>L¦ÚIZIçJnGz¬Riu3ù¨°VÄÜ`?́/è2ưÓôñÁR-.%&°‹éƒ/Ñ8Ç…Đm~á“qE—üñOGqœ·¾F¤ÑJ„ơ:¦ LÖbGl43#Äeè‡u~~«à r7aé,YaỤ̀m¢‡ư©đ̣îóá­£NMml‹V ´Bl$}…WKt2¶$Y»§ÊQ»0¼„-Ó#ÈS0Q|ÆEÊ®â°Æđ͉ÿ*ñÀ¦®S¯miAÎÉ̃Å2ÊœíàCØbê#ơ ̉)ùSq #„FP< ‡Å.Å@Dß~ mơ‹ăø7±F cZ4†_¡5\|j 8¾₫¨l®0>Ñú0è>û¥ ‘Ư^_Œ‡ƒ©wÑê<́µá»ƒöSÀ¼1Ơ¢Lp|woe–™&1ÊͨâñGm@Åyø}¿ø g†–å’¬œŸÑ迟üï̀å•1ƯÛï·¦ô° Sú¸×¨Í÷8£û×EỤ̂åm/ö́‡“ˆ"·=ÁSÅT cRè”®Î~uDbÁ‚öÖËơ 3»oNs7Ÿ©îF•7G¥ö¸“ÆÇ;ççÜ#™.jB’°¬bª‹ªN›a·b¶‘“Å .r 0LËÎä(&9V·Đ>ó“ÄsÅ ›Ÿ½Å&Ø̃8vŹŒÊ>ö·₫Í''Øu)Ǘ!mñ̉'âÅá»óß»Øùºÿø`¿k®ëœ³J›Ó%!çå4ßO{æ°sL²Ô.è°”Ñå’7ø?C÷¯Nûj_¸=1¬}'jè2)r̉WÂé6ñ̉&z¥vhH ( y#µ¤ÛK‰ —¹ËË·²1ÖÉÉ;Á`lI˜BÄ I©A$ue¤JÜ*F¹¢ê­ˆ¼$‰¯ÛẦÑ‘1…äRä́³*G!B_\íïÁÿu`”Ư¸’ă!ç¼£@@zø:*¿€aœèH{3?áx7OŹ@:BÚÇÅ2»ŒC.©̃6Oeo1ß‹TP2=×r44“åÉsB·À.=S8•‹åp™øÓ˜jS(w2ùFỢè/mNDr÷F¿"' V:@LWœÅqçF½rt́‹KXiøv‹8Ç=ăÈ8\ó×*^ïŸÈ-̀[vi®px(È—ùiG ÀÊ2ç9L"Đ[‚'¢Ro¿÷xïüèôÅ›Ó.̃Ơ}Ø;8èßooK4Ó I·Kˆä¾÷­N5à퉡uÄï¬^$<«— ÏÖ 5"· ˆÛ²ẩûÚ+qµ IƠk¶˜„’¢7"ư°äb•{ FEb5w-nd”åư³~ÛQç,d¥·Ê_úN¹]!̃«¶¦T˜P–7àÛÏô 0ô‹†pđ‹-2.p̉î ”B X2'áסؾoÓ÷êHX’ÑCiÆƠåïÅ¿]U[Q†ÁVßC—C̃{ÔPU>GDÅ.¾í\È+™'‚s¯=3 9w—Ă[)¿âèX–%a%]qÏ)[yÄæTÛ©F™ë¤¸9T:~°ư±ÚdyÁÅ J̉ŒçXKñ+m²á`ët>‘5ø,->4Ñú-Kf ³[ƠÏÿ•Å×oDéç- .9¢Sø¥oV¸ä`ŒŸ@]ɼṆ̃DÄÍ̃‹ÂëwêpAÑÁ¢â…8Ûƒïø(æ óĂ—GølC£Çp×üđơè_́ñ§G—́ÑĂˆÎr·ôʈW€{NÅ%X§b½Ô¥₫^s+†áÊUsï;"ưw’µ†ÿt/öPÅ%=³ ¾ÇoVœ½A›«^ôÖñe‡^[D€¼€+¯^kî>ænØO.5‹C¢·ÍàĐL†o₫¾Cw*ö+r—âsé†*¯àđnûTæ.5‡JiZ,î•Öàû›óö^kĐÔ%ÆNî’œÆ@|îôó·™¿K±Ó7˜ëF½Ự̃yæÔ%ùÚsñùû~S¸¨®^K+%)f˜̣a’%aÎ\:B^,q‘T2vÖ.”lwïAå£b]æăĐ=¾ü¨+¿Ăw OkÖ¹gI(Πöç çÑë܋¦A[êÏu4ƒ ơIƠ ‰?q •yèùxG’úá¹°n%¤sF5ó$™å k•ÆâUë¬ứ ö;GÆ~Ö ₫¤kư½\æZ¼ÛÔéVŸ¤¬ ̉́¸LCVÍ]¶å̉đC!ûäó_A{O}ü­¢qÁ¹-(¤²¾̀%L´ÉMöø’ÅƯH¶$)÷ª#ó"Sq"±=Ó[Ĭ¾̃†a™Ö.7TĐPá1ắ8}BoD‘̀”Ø4BŸEØ•Á?X 4JÊCĂ ‡ˆzÅ]]‹éàC>¥péHź3ô†WÏ1–pP¹\1¹ï”|ÈŒkíÊœ½˜8| 4s¬ø*•bxgØ dơ}áO& Zº‚”б̃gé%êú‰Úơ©Ïn¤ña"̉UhPú!‡Ÿ̉FW#3¢<xEä£) ǪÂóÈWYƠ˜£O‘Vkm^ưÄW¸)+Pij }X·Ơ‘e 7–Ï=QE\3YeMZƒ§vÜ4¶wEÄ‚7 (-ẬtA2 Éx4ôoc,ĐPơáqШ1R™o¨èĂsYßË [#s9@Pö —uTƯOƒiÆ%î6,cDM¼¨pcYƠ8¶jÄz§t'üC"¬¤‡µneZ%wÎCâ:\Íd<z­Üä¯UĂW¥HU™Ưöï–©üm{Wđ(—z{íEqH£¯p+üRz¯ÏØÄôÖªÈ|ê_‹ÆÉƠMj́÷vN E¸©ÆUt[¶c_&Æ.Sa©µÍŸ¼ë°ØaóÑŸrÑûÊDS}/ZKö»Tü gƒ’Ơ·V0áT¼_sV4.ÂÁp¶È´tĐí ºiu»’„Ù€¿ƯQsùË•+ŒHllaÖWê×_Ô^×[”Âx#W##¾Ñđ†¹8€ëÅ\i1«|̃I0NƒÏ₫櫽0؋̀/L· ñó€¸[ÈMơf²‹÷ê˜ K×QĂœô$–«Q@Ö,Dpx˜ètÂÉXó§zAj$æóßöü飀ể"N>óå„B[$¬â.;œ`iÀ0¸Œă11_’y/Év{‘Ă• uY¬8;äêËæ ›A)íÂƠ•z¿z OäÜfólƯ2çÓ²cÿ{?аSL|ÅÓ“z)Ë/ÏÿăyoÎ{Ád„r5 ùÂ{Pạ̈đÚ=®ÉBÅ-ƒñë½£p≄Lk 0VVC~²U`…[÷RÈëQ0ºrÅë®øÙxMáRW<Ÿ'Éœ[AMă1¹3C©'q"¬¶KJeû÷œ+=‘kDA{¤OîÀUw9ÆOR$Ï]‡«øuµ«’˜ïû[ƒö“ûuô`«ûĂdeAA8(Éöë…ơw1i¯ëÖUí/¥˜aÛ_«œj¿ Aá4ï›­^©J_+©kiŸ°µKëơ›¯hÚo>_á«ÆyU6 Œzăi¼´hÿÊ~3 Rơ`*̃ü5^^´¥E/ëUf§ lm~₫–Ô•Æ:*Âî©Êu“¶•D]´M–TỖéΩE#Ë’Ơ6r•/1°¢SeA•åA}«j«é¡"ëĦÇIJ€am¢4öº(ïü§¥ït¥¯Ă²-Y)I§o»é:VR7âÖø¤ÈđîÍ\Útó©eoÄiéÅï¡ja¹{&ˆĂŒÔWr„å+ºñê,Øíº×‹–Mpæ¤Øiobí!ö`Àת߶jCyq™ÿG–ÿœÿFa1ÿíËúĐ«¿́ó'i9—‰1"´0(üjñÊ«}Vê-‹ŸÄBVùaơô£e=¿ª¥*ayÊIT°]¬Ër…ÀYŸq×`‘^z³Ê–>6iRkÉÇƯ+¾¶•‡§3ïÙBö‘'^ySEâWQ'£Öo†,ÀT1$×êR« H̉”$â$åTëœkrfƠ䇻ÿa·.®¾£–Ÿ¬ ±¹l¢̃:§mê]D…¦Êe6ÂH/ív#á_k÷ø‚¾u´bjAzk½Ç¥Úˆ¦¢cm³qÅ5q^°́èÔ=—«âÊd¼çn©nî A¯uÅM[4Tít;][˜æ-}îƯÊu› ‡ÙúHË&}úÁÇ2U€'„ø³røÉHÅQ“Ê^·¿&H·jo»̃¬]°‰×F°}vY¬¿îÓ‹Ö̉_ 鯃¯ḾH¬¯=?ƯP4¯Ù¾6Íö‹­F/æ×Rü³Í/ÖW¦ơ~­‹UƠÜx̀kÙ¸F<øÚ4âot-›6~ v«,›V|åN©µ₫;înà ơ˜^S·vÖQ®Q'ª“<åjuê!—Vú­%CkY¹²€Ă´nỶvP£„ưμ¶ºlàÓyJNQÉ­ˆD¾qf~è¹X¡× ÁBAÿ Ñ¢k"+`Ü—£ïZ¹sá-9e0‹7² ÇóԿͧ3å7-ï²=¼ă9z˹X´¥Ă;•‹8±—)DƠÓbq±s!•mÇ3”X3hl̃/ º¦<ª)”& •- r—Ú4À4AÈ)åưAÀ}µ©úôM¦Ü™3̣©Â.°ẳ¦“›•̀üä…–+‹’@I+2‹WLȹT4r·Ö‚¹,ÄÁ̃à<ñ³í¬u q‰8Z?)Î##‡~FʪNç÷ó­ún¿;sÀïAƒ̃V†W}`½Yÿz(ơ?>Su†ÑÇAø×G¬hséÊnZ1€bÜëQû)©á³®…*…ø©  W§ÿ©̉—¯÷Đî SѺlë» ´ÿie{ÜÍơè~zt¸0]÷ {_ĐMkỉa#™ºèkÓ¥Ăí’m7‘"7ª·%‘×´P0¿2uúË-Hƒ}Dër¡¼¼äوגÊÈ÷®x'›yË™‹#›_É" •fß ‚eN¸₫}íc“7LKñ½È‘oˆÊRƳ$9.úŸrM|2?¯%·V ÜVï9“ííZ6nGWc»ô‰Êư@Æe$9à¨]ĂnºeZædQ‡{1™w»ªïŸ=ÉĂœ­PC•V7U¯rª¦]˜œ¨j‹gLº¼4 ̣ïÓn®´Ø»Â K£ê,s¿$n©„EËt¯¹|‹9ºOMáq Ủ·JÅĐY;r/{‹´ĂJëºQmG¬Ö›h­°VÿUđp½YÜ“Â"ÈcÙ“Ê­é=´K–*ÆCÖª‚ ơ~~óG—Q±»Ç»Mgœqg¨EQưMuJµx€U á“ `<éÚaw,´ǜ=0ßê˜ùR$0âŸiˆgU¢æÔfbÏPœ‡N«ØƠj5o,­ßFe¡gÂP(|^"J'̃.“¦Åç„%ƠPTPăÆÚ½«-~ª!V”y*÷¶v;´̉¯>—Ö»öM{ƒE+¥Ưö²^@ T]³ÏMíÊÂ[”ÿ̀Ö¬Â%ê#+úí%ÛP±³ÑóR9íø\L‰Ờ7†lÊW-(ơM7S½kñ0]:AŸz5«ÜÙ]Ị́†m¶.½™#kq4×B~™Ç•6…—J$ dW×H·_²—¦aÓ6®˜}PQĶc²₫€ĂM~)‰A6²æº§¢uø¬3èƯ ă‹~¯®ƯU¦bG´Æ×Vͨ6Û?ù$ăOgAû? oQ$äQî =¡ùÙTÎnĐ:́tåªÏØ?‡‚Ê…<à>„gâ0üåà>>;è·ÿ…- ¿Ç–Gù;®N̉—ÙY‡̣ß¹B@ÿ©{on˜6è;ôpïÇ1c%”îàà_ç IXÆÁUŒ¥¡ñCäk—Đá Ú´hƠûöĐ"Úô¸û©«Û¸> l B́?°Zö©‡ëµêÍ}ßçw´åKªĂ‹LÜ[?X°k³V»¸¾ÑÖVÓϨ¬'C[¬z<p3߸ºêQ€¿½ú‘¸ R'`Z“ÜÆ· Zl¶‰¬X˜w£²}ọ̈ưÇiUú6iûÛ£|¥LmâP”~µüRÑ:>y×Ö5_­æç@₫ï¹—, çÉÅTc.³‹“+“«.e~;k̀âÍó,©Î_AÂ/e°mØ(«;À#|O%6GCÓûT• ƠZ̉ăh.Í9™¶ª₫ÄÄɵ ̉0ûE"Z¹v¬t¤“ ẃƒh[į#.[Qû™×lỘºQÛ.¬$ÅÚ,UíL;l$VXĐhæăSx„C,Ư¨Ë™A>¿•öj ®{‰€ºFóĐX&eỡÜ{́\\­xdTÇûÖ†[ÓrÊ¢\LĂ ™È¿*ư–0·§Û説ît‘Øø¼`~†¹˜àÿ‡-JS0‰Ú,×â°̉?–«>3Ï̉e7ỲfĂJæâ¸̉?s¥Å¬ Jû¨íßn¾àK‚K©;Kr•v^^„>U=#oÈ%åÚưè3ü^ù½×µï5NcŒI XhÔÆæ¥4Û2[g$Vç7^²¬)Óu*¡ü ¼,VƯV¨'“Ûú…F°3@,…‰^‚lÍUc2?{§kiD¦Ø)yVtIEÿ¡K‹²¶k”¢ç¤\)‡ ¼^T]ræØ^È™[h®i»¬Áọ̈Ut©ŒĐÖ¢sz‡̃íbÙù@đ]k´zPèô@î €l²2§PÈØ‚UÔ×\Û(÷C!©Q6-î>ŔëÂ|S‰p }»X“ƯçW}+kRUÁb#´Ấ ]M¥©«.I[9JϼOAö9½ºíüˆ E:ă ËÂê†T(y3îÿÁRK$ZñxÜî©r”’_2PY•¶Nµ ;ỦÁ¸Đo}g*n¨x&[û¤-îáK:Á÷ư'WßĂăV •S V oyר6ש7­¨ÓÇ₫„aUØœ®\a=ô Êt¤]~#DD^å’_åq”S—ùỊ́ë=Üè -vô0áAû¸É<¢Œ,´aÂC^ˆóDz›f₫T Üt³I›bqƯi(¸ưÉ6êepø0í)1Ÿ©á€èEI=]n¦uÁnƠOX¸›“óåª[ư ƒle ¢yFK×Kë©c9†#ci2Đćˆ'"ÿZ¾©¢FôqUĐÑ&é`Æ‘/ºp\>èm̉Å•© ¼¹ĐºưLº ´¹‰«@?6]k̉ƠË?Û¯Z¯î3¦úŸˆ~-’5wAÚ5·®.pæào/uZàî@ô¼]™Ùæp³ǽلEæ̉¨XcCn>È®ߥ Áêá‘_ÍJ,ñÎA“r2y•ö™ă4eLܨœÏc‡{8ª¸£®#@6I4 oPÚ]|̉A´’÷­qØ5äλ„uùŸGµ»ós²:›4Ûâ |̃è hd5KOØ;S¾Â5¨²·ÄáVëÓ¬…LƒmÜFöͯOUfG°‘mÓ y)Ÿ9‹“̀ê Q»ÿY‹̉aââè·ù,Y‡xwü¦Ẉß©ɼac|ó' <ó°}r«ùz3°5²h~§̃áP>héxüª:#j½µ d{~–<ë”Ô¯U)‹“ v¥DÑo«nkÆ»E&€ä'Ø̃Kqó©—.©kU—jV…́̃ïơÄ=Aboa]L†kyp´¿z× å7…bÂkVEÅ/˜û=®ÁP·SZA»]Vßê9ÙB gêP¯dÙ:;ÄYÆ7Œ_CSdègÔ]=˜¢‘³YêFPSÔVŸ¦\̉1™ñ¢êA9ÅQaZ§™›́I€ Éœ;ç¦~i‡³L¶?Ă—è¤Ÿv̀ăh¡+>­ª‹RwAs:`%à`¢®jSệà©îW—‘©5\êÜÀ* §²9F3F™4±aE/ɨŒ#Kÿà3G.o¢ "Å·n/)~Î ‰pás¶†|ˆđ ?g;Qq*w®â\ â.TÀf°Ó”Ç‘fÙ8̃¶£¾̃ e¤ù7Ñ-**~…m*Ê—0³Üûz$3ñ¹c"Ó¹{Û<« ́O3; Ss]ªí—f₫Œê† oÅ5q¤)}‡Â¤'+›£sM7U|;ô"nÖæˆk“‰aí:O:åéqB¨¢… ̉\ʵ›§º1U ́ø†H1Nä;ä&pè“S÷È.ám;W3L««›³́'+Å ¥?N8*z{¡ẮWgÈ Ç©©@¦¤;HÿĂº^ûƒ§K2î₫üç\çYB®N¹¸€ĂVç·{ƒ{³à^k2èLúí½VkÚé·ï§\VûÏ4»./zñ®½©#<ù¼|¾„GJ#‚çí=d05é; ¥ÁÖmƯP±kXÄúL·ö´ăè»$ư÷<~Ù¦– hå‚j¡6†áÇó$ÀZ zÿ?á,Æé3öt¶n0ĺ™…”½)|ă=ë›Â qĂ{–" nd—ƯƠ[†À ̀Æ¿± bΧQgxÛáO[ QăÑ!êÖ¢̃öB€Ù…ES¹k!æ̉(ëBˆ;¢ÂNS¡t4ËUƒ€8È!HXg¾êŒiNR•y³Pƒ´̉ưI‘v¦ ơ₫9L%£`¤øI0rXÆ’„x8ß“Xg–ë–ë6W­̃mœPÔcdáẦƯ¨ÙL3R]’@#àYi0\́̃ê'•G¬·[– æÆèQ¨-ÖU¿BµïWJuơRÉ ÓæÁăÏi§$ư¿>\a÷5 ¥ó©¸ù}Äñ‹Ö,­Aô}¿-®Äœ  ïđñVǺvAÎ́ŸèY¯)‘pƯêaœSúï$kơ÷N9wđƒŸèË|é̉[úæ-¼~¹“ŒQçgŒÉ‚®… ¾*ø öÎ#‘È䨠Ö5°—¦˜"‘ÎïciƠl}“p›N³‹¬dà̉çư1Ínà`ƒÅ,́!½w-6hˆ‰mƠ»b̃®öú¦l¬évr7Œ¬­¥„mÊănû@ w`*h©e÷ÍR¬~Ü­+t^.–˜Q.#ê ̣WÖP4¾ư‚‘è.6í®’)¹©*WbSæ"u"ú÷ö]„˜ /¦Å$Ù_‹ÔFè1@ÚE¦9mŸ²¸ö>§­c̣̣Å¹ÙØ\@nmØä¸—j÷)ªu׺¶R{(› nÈV…£¼åƒÎI–̀ưI~ç÷ñŸgÏp¶Q˜;ÿ+}_ü£î¼w₫Wyç€nÅ;ï«;ñ»:1ïpÁpUúÉ<ä1ëØâP„Á•/~›ù”ÈPÚOP$Ă"̣XËŸ¼€öƒ›z…i’̣²ay©Đ“†·0]¡ư pu-º¿‰V…·hªéFXơêB8eÚ—Ë—áeW₫ S^ÎÉc#̀b2̀En>₫]×ùĐONÓËă™ ¢¨Ç¼‚"g¥ "ÁÙH:µH¡%¢nO'Ë âà»Ö ˆ“Æâd[‚¸bXơxå°j…Œ;§¤“)©-3lDߤá°‡9¨²̃^Đ¡¯)^Í5dXíWA„xê–Ù$”Ñ­̣U‘Ä„¬z̀‹{µbR)~Ạ́Ø— l-È #±W$³×CV…á¿È«Đ e‚úÁ¨묦ÍÇ$³æXnX·¨’à©N!ÛD’k.È:½½˜p=·z¯A¿̣ïh€ŒÙ¿ª$‘†v¢‘nTV¬€²fĐ́»K"©ÀÍY$ßÈRí<Ç„^WÎ29/@«ÁUR­Rgèk­à`‰¥«·É÷$<Ư#Ó”bå, ₫ J±+ÚánR[Æé'\¿'à5HlÚŒ.ƯÊ ×<9M¿„û.mÜ}—nå¾ûZÑÚ˜M4]ĂïgƠ>1ö»oÛûg{lÜù§“Ô-ç_µ‹®€Äÿ¢”üåî8ËÖT}ÚÍÔxÖNåNÓ4x ỷ"r¢µNѦühÚĂå÷Y_ÚUÖv@¥ êëe„º/à5ơu3„úz„º,hÍkú§5­ë]Q›k|ÁFçºq½ÿÍ-È«úr2?Î6]¨†½e×[ÅƠ₫ç,”«ËÚ­¿dË=q/Ó¹ö€æúV½cÑê¿l/•ƠOĐ]fr€×*t¨íAv®'j°¾”«WYÇÏ”÷r2xy)µ)Ç*g„ETâëµ}ûÈïcÙIâõp¨¡y#ÀÁ-0Ưă“w€o¸̣ƒn³±d ?®2,³×Ô t¾u}3Ï6_Øù²…%ó()̃†ÏfI|°9v)¦>­[ÜŒ<÷…+O~›n³—ˤ‘€{Öh5{Ùˆ4`î@mœ®¬ß¶ ›ăMX!¡Ùv±—w¡6̃9Z›R =#|÷ơư¾"„7—–L¨[®ĂË^¬´c-µW^’…₫­©‰…t”̣9"¦nRuy ZSv QöêE9“jKNUóP§µJ;%ۨȣÖq=UA?&5•Â~‚i€­Ö¤ [IJÇç¦K|^E‡á^{ gb+ÿYi>œEª[¶µü›‘?ăzsC ¾Êe†·ơ÷NuªJ-ȶËù FPà6ĂJrT<Đ„–jVÁª ƒQu?49‰Ë̉Bà8$»Îßü©Â¬ß%¦«|ø -ÿ/OưïàYïÿơß§₫ÿñ‡àă½Ö(N?üÄY$Á̃éGñ=Źo°m€=Ù~ê'î$u «º̣‹Ă3|¬{¿?ưaahỆ888­₫“ûùà‘uM„̀ÓÛ÷³¿^*b́ ¼i ăº!!ăz;)£–È^oIe722ólå^×ÛÉ »FPc|ÿºyƽçÿr¨«¸""v½ Ú÷@‰.;¯¼±7Ẻ¾’^r%8E Fh¿ũ6 º™çç¢e5gû6>°”¯/̣äx˜É~\É©½bë5?7xé4Q̀™9n•æG”w,+¬”báx¶H±%×XørŒ",-JS¦ ³4ÈÔVv‰_"?qn/¥KåZă.Üp&,1³:¬––Ǿ“\ùæô’h JŸ•ƠÇÊQÖö+§̃-=ƯICrƒQ“9TiGà©L-å¿r;₫œ65Đ¢ËY=+½ç:¦K†m“ éT&VåpǵƠhmƠzhƒ„́Ø 1¸É 5ö¥‹¿̣ă[oŒ6ÿcâaƯ püœƠg]¡ÈÑÖlq±D¦¹/ä}«‹5đö’u&”Ë•UO-˜W}ëÓ¦ƠOÂ¥Üë0̣ÂÛ,1…TƠ†Há”Iœ¤oY W( ¤«6RE ¥I~bÊËD"7UßÊÉ©¾6&¨căb959ƒJÙj ]à…øÔ\¹ª̃E)èầiç%QéÛt•Çkj>U\ª@7­N¡—%„Z¢AbÀÂEá2Üu+#6§̃ź/,5n¬”&Ev[ñö¥[¨₫Dé¡c¹±È ÚFÖ ̣i§¢û¤ ĐÂc,· ™^,Rœ63Ǵ_¼œ>ÀBW­à8\é­yü’Œi0«‡°5G –Vpè? t†ƠyYĐP‡`Ë*:_¤₫CĐ|ˆ`Ë _-f›2 ëPVÏƯ‘p,íÂÈ <¸Á"N!¬‰"N±D}‰å«Ôt!‰5ªFÈrÖÆnT¸"̃ê FDµ#® µ"¶­±qjÜ.ê6Ë 7ộ;×c]ƒ¦x×VÅvBb¿@Ù‡`u‚m ?|½ÈƯ}Ɉ`5#‚m‹F|Í ²ûrÁơ&#ÛºîDuˆøÖu'ü€Ù̉ˆ´';Úˆ\ûVj‘¶đƠRˆh€‹,ÍyD±ßëđf²g‚¯-}&ø"ù3Aó 4Á×–AÓf›ăëçĐè ëç̉Ü6£Ư~%è¶a%h“J< ¤¦Ë£A(2d BØP»ELÙÆ̉¦L̉§ ]MĐ́̉KñpưGÈ#©q9«̀…;%,(Ju;-Nú˜øi0;¨w;é"ö¨÷T§¨‘ơà'×mçÏøxơ•N P€ /tá»+øJw*J¨c'¶î™Åá­hơº`ŸÊ›™hơø4Ă_zƯ¾+:ô»×Ư§û±!ĐŸ í4.@7¨Îè ïözXÍ80½Á}l®ù”Gu)²êQq`¡ê¡”‚JwœîMzOdû´Îđ₫S=¡œBxø"Œ3˜ •pÄ Üĉéđ.Wx®È÷ú³8›ù>ö’/úpëÛ)ê±tDëFtïW"D ·]ßxè/3ÂhÀL˜|₫Óo“ø"ñ¦Ô†A¼ÄJl0N™V₫V7`€s wƯ89::‚ïá[×/#ñ>@}ÿ;X §â ö©+NưkñÏ8¹>~ô¸Lº/C¿+Èx- ‹BUp3ÂSÖ¡8Ú4`ª¾_x|áHi÷±Â]êºP×́¯Æj‡$yÂÜéâ×́WØ‚úE²ă"VƠ‡m-~ư•î[Y•^°=Û*€¼ ö¶–]¯Î¿4î¶à`ĂÚlÔ¯„ÊF5̃"ôÆYT¥–¯ưU*4UÁƯ~mµF¡7_èÛZ›‹ÇiËÖl/Ï"ô-úz₫̃—­ª,-*ơM,ꦡ[/êƒ?u³E­¸:‚¬‘sü`§K₫°y³đë¸Yá³̉\«Ê¨¼Í„›’(œ*QXêË\ ÿđƯëC1…qX9iCP\(5&gj ŸE0ĐÔâ›ư(…ÿl;7¸}]½LcV÷üq9¨<:ï¥Ø½Ë…:²ï-Ü%­^záD~-i„k£T~y}‡¾ǘÚ§ø´º ¿¼Ä+æ¹ñ°U½í¹ H%ù™'³Sv&™¬™ÍX¤*ç°éL#›-©x+Í̃ÀUumn|íæ£µVă4`«1ău¬Íé‰OÖ»(Vf ‡G»€H3¡‰Yn—8f›à{í¶ ̀‘ZÈlm¶ó̃Îéx‰B4€‰ü ·­®Ù ·W… ´]¸.Ơܶ`ơä₫Ó&DÙo£ôؼÿæ] ²â É-±Ü¬̉ãô‹c¹1ÂÆÓ®` Í¡¹PG“²º=Ç]!o ưN7ơ³Ëx£jö$w…½»båœÀ–ø[(oƒ¿G»7x2ë̃¯ñ<[Ứ¹ù̉lŒùGË5|iµâÍAÊơ/¨ơà'ŸU‘]·âÖ?¯qÓtă§v×Ç?¿g¿¼^ëªƯ…Ë«v±í¶I©́×¹f®I/ÅDâë(́P©:̉K(±AÓçpÔ⓾ư$ˆ₫ ÷AêSøæÆª-‰Q ‘ŒAÏÏ<ơÉ)YUÉàƒçO®  ^2œ'¢uă¢ÎO]1Jà- ÀT›Ä‘:‚Äá>§ú´“CTñt€đGL½rz¢°Ïdø…S¹ö«EđÈ¡r‚‰p!Ÿ® SmtK‹j³¶©¶$æXÑE¦”:$QÓơB5MƠJr!W°ÇJÚE³E ±×ëU4O²%l +y™S:êÈU=—r¯}æH¼ŸóXK-ÍÏÖ ôWkÆĂ[ f†¾A ̣v—›{Â)Æ_¥¥ƒÊg¦ÔbNz ·ª†·°ºØP̃jëm„Ô¯ÁDE3åN„ ›™ÎG— ¢NÑÓp½,Ëé¬îÊpk…9 z,̉ØáV‡| V»ơ]ܨÍhøc‹Xµ-Ă„³¦, Đô;ăû:úá©cb³B>0Áª:øîÇ_^Ÿ=qÄ!F‹Í3«† ú°5¡&CÍ=¦ »₫t–Éî~›kåë{îN½äª3œ–(8 Êù ªÊ)‘Ÿ×ÏZd™À|̣J¢œ3IẠ̈eBáíl‚nNùO‰=‡bß:¡waƒrU«ÙđÚ»MÅ%í)Z= wÇ9âø«æđIÍ!điü nGÖb·ß¥î8|gl^uÀÍAtª /6?ƒÅcu–́6Bè°ẓ°;ǛÓỳ¾G²+8&ăăÙ`K ơV»ÙQÖựů ́V@ضLT©ON•Ù­ơÊO²Ïm îY_Ú›Ëbû/̃œ¿{ósḉüƯÉéBïnñ]4ö̉˧0Ă˜O}koa]‚1BsÇñÁĐ_ÄÈ&Âa= k.Rc:cj‹)ÅTßmÎÛ;ÔrtC¡ʦCWăÈOƒ±±>±PÁæ?u¨m1Iâ)ím1ŸQgD®‚hÎÇ£HRɯ“½œ·li£§"ÿöç¼m3›âVÜăKppÅ!Æ*¬®úèÉSꘫ-₫år€SƠ¸axH6($‰₫uâÍ`Eb ¦’ÍLÍ[¦{ÑÍ¡„²aD¿×!“rÍÜlë%ƒÀh 4 öºûđÿ}øÿ† Ư§˜!ü5 @"Àô2˜dE0& ¨@;­=‡€ịˆ;Í)a9½öf3/&ă€ñND÷Œ9‚$˜¦†èåH²ñ8ô»¢…•2tÔg&’đDè;ªÔÆ¡ÈÊÀ\1w’!¥¸Bá̀…s¾€jJÏ£Ư• ‹]`·wùࢰ¡î/ƯncØœë×$2”öDO㉠Å‹œX×D̀ùAIF?Zw{Qè᤬Ï8í>ïr¯_[ô”hDÁ1RZˆœ˜ê¨1̀]: "¬Ï †ÂUP<Ø*1̉ ‘ưD £–0‰:zñ4¤ a„ñÅMÍ÷·Åïá;ø¯t÷RÇ˧N™ÄèS‚AƠăÇ1qJG H† ï#ßK:üđnP6¬LAÔ+C6fü\=„—Ơ™è÷îÁ”û½¨ÉmuYI«Ú(ƠyNNFEæA³qF,ó")”¬|" ¿;:ÿåƯéÑKñĂŸ9B)ódbâE•$AΡL$Ùß¼§B́WăÁáƒè²ăP·‘Eµ!äè4æ9¼̉äé,J:‹D6c4qJª@Qlywt|ôîèôÅ‘#>ô?#ؤ>ºƒæÍgzƯ?Đó>˼C"ö®)́R¼öôf₫=é>A/ö™q¡q̀ –„<"¤I$f~BóÎ'4|œ‚2}t*8eºâq(>½|&úû½Nÿ~₫:?u1ó oÅùoæŒÅh®XâˆÛ|Ûê8¶‘xÄưñÄ ̃Ô§i…àăR{ܳ5LqŒ¤ú„±ÚHÿrIƯQÜQ® Ç×uWcĐ¢BoVwÙ ©´ñ₫jŒ¼åÆ~çh#:mˆ¥ùGœØy[îc<Àp̀X?WÄûFñe8îüQ« }ưE-̃û!(6h₫zÔÆÄc ¸̃3ö ófÚÙ°Ä÷ÚËBo(̃ơûr4\©ÎKÂÀ$î̀~ÈËvbvï”CD™x́§£$˜©|m+Ùà’C/¨!¶Œ ư»©ÔɈ¹’ao-˜³†%¹ëöUuFË}üpe-ÿ¨!ß₫hK¯~ĂteKÿh[÷kư@n79‡£æăF[F4Ÿ·{,W…¹[„xƒEh6Œ`´eÁïaª2²mv¸Á"5j0Ú2Èà?a‘ªjqo˜-0j>̃a´e¤Ăü 64j>c´e Æ‹{7™£æ#IF[Æ4µ›…yŒV đĐêƠ(‰Ó´"Âće^}seÙ-UAOÚ£l%ËYªe­^z€5©íu›¥ªÍ1ZK³iF±!ơøn5›»3˜¤ăfèÔ¦„fKú¶8™¦h4©(L·¥Ơd…: «́%“Íđ"CI:₫ưZIÆĂ y 1y(ø¶Ơ鉻=IaH»ÈPsºëª#jF+”ÉÂG,ö(úa*ZăçmrÔâÁÈ×W̉.¶EƠ;ƺmD¹$æLEq‰€½~OüK´nöú=5Ơ5 ›(¯*pB¶t_! 0Â[®­Iq\#l,®q?±*f™aí¬́¯Ÿh}èô{.v½è÷>¶ï’Ă$y¾ÿ^¯'úƯưÓ£ë¢5×âëÁx¸ơiŸ¦+¹\ uăê'̃€̃₫̀+Xß–Ôà́뱓L6ªgh°_Ö^z7oÔfj0·›ù²¶Ó¯bAµŸ̀îfÁ¾¬ơ›X°m©í»YÍ/kSưöW³1»ªY‘Ư,ô—µ¯₫®ºI«Y¯ƯlƒØZ7YÛÍ́­fkØ\WiÙẸ̀ÚuÄF.wn{a¾Úê@Đ]«kOèöªúµ×ÜàïÑ]æ“n›NJc_‘¶ú(S ·Ëó_Û¤j'ÇmdqƠ‰›P¾âFX£û åWÊäÉL¬É;*4QÍ=t˜>¢d¨å´aùơ8†s̉¹¿“+ ³j yÍ‚„&̉É<¡|œ±ŸyA˜Vf¿é¯¶O‚««û}“Ắ¶€}TƠrÈŒ‘·Vk¸]îQûA@Ï™\MØ´]́*f˜•ó·aS÷5²SÍ †Kƒ]#ÏŒ~ÖN6£Ÿ*ElđàáÇ̣¼ÓY«.È<Ó`ûËåÆw~fü f¡ƠmOI·,¼4Ÿf~6ËS+<¿fÆù©Î]+¤œ4˜Âf~6Kf³F¾EZ›½ܬAm–êVÀ÷.3̃̀ÏF¹oæg£,8 ñ çĂ™Ÿ2ằÏrä4ñUP™Đ¬—-W%o,N+ñºô9óÓH"ùi*¥Îü¬œ\g$ #b–—à §ÙåIJ wæg©wægIxäuưtºaÁÀYªGX.=èĐ2+µeiàyä#Æ:ˆóÙ,NÙdKưj½QFmăQ›¡Q<ùÜIÀ‘}ƒv6ÓÙ€Üë>ø ë‹ÈB=©¶ê{öäc$¬(’H5 ‰8I#Ö&•DïÆ½uß®¤E.̉÷8uëJ´ iXs5q%¹p™,¸ ¾cÛ¬ÜuÜa >̉|-jüºäˆ»œ4Ñq*®pS\Ù_Ư´̉qß×¢kLâ!KÈÊNí€kR/d!YëêViŒq°ïer¯å{›Ó­̃¨ǼYÉùO¬T|7á(¯„ṛ_Z´]½đΟŸÊאָÄ8öÙfäcäsGÍ=r̃ñ45.b/ô!¨*gÁ‘Cf CLù¹À¥>¹,†J°̣¦b½Çß̃Üü: Ê[½f£^'‹vû*{¾½ú(j\ă(Ÿ=u¶P(&ÀˆZ¡;â´ ¦›UÖ¼²ûJåꀘ¤yB狳‚˜0-csö©—‘L«·_4É•0‘-$âz°N0̉[Äær^ʨRsØĐl4–HÑ©n6^̃ÚÚ6W_¾âè)||*—‘\–º²V%bă(¼ED9 Juçid-'™9oW`û₫‡fl#Ơï“fT¢”ù×UQI˜&‘Dină9M+_\À»€à\ÄñX’1W€*…ưu pÀ«]ÀùœÅIV‡° ÁĐºE®¾˜eTåw†ÏJËV%aẹTQ|hµ‡3—¶6¥·iæO;̀>ˆ¥H†BáyËƠíÀ$»YM)µ†0Ø|OG¯µ´ứÚ‡Ữ#|÷Ÿ‚‚YƯù“́Øô‚n₫á—̉¤)Å·ổ›ă’bƯ‚h #’äh"ï&É¿Pz-SùÆgTq^v¾i·¹“±êøL:Ñó£ï÷yÙÙôT Á]9Tˆ®*›¯&ME„Öäê#2$^娅ËA«¢ßRz÷©eµư#ñ‰Î%# –̣»0{úLĂÄ¿D¿ÀD öfyï3ôg—¦Á ç¢8Ÿơbqaó¢5ûRm–ü r/'ưËḄđ_nÇñêziyád¡÷*E"Ç8Ne÷4¸ùÂ*n^–Ă©’’àÛ_á%:)yZß|;Å¥̀đCø̣N éZicQ,¤V8P4~yvKÚó5ƯUÔUy^-À+ă¨M4W¹ç̉ dámilUôT訢n¯äŸ†µê¨(+(à̀ˆùi–ø_Ù;“V¬sL7¥Ư”a‰Œ~°•Giû·$QØ,Ö–¿l=qûº°}Hädˆ4Hóæ%“ ÷iP jN> eu£ËĂđˆơ%¾Ÿwüáß+=ë̀y¤Q7¡Rª@°V{‚‰„Äă1R˜z…DʼnrơRgD·̣ åYàV,œµôÖ¸8d¬@b†™GÆr%z•$¯¼Ơèæi!H—¦~ש̣5^˜]Ô—fW"km IV:taéè¹Å¹» ‘[wœ¸¸̉Ù\+.NĂ}÷FVo÷2½=OoAf4·p¹4Ö+•µçÊ÷gªp\„½„$ƒSF9>`öµ²@gt.e9ñađñÂôp^ˆ)ü÷Đ¼ÿÀĐ<ÛáGL놸̀m»:|nà\n–Û…Ïư¾ơGø–̃ ÚÛT̃ QLœqV\HĐ¢ơ™T̀ẁ4‰??I“8Ÿ²Öbr‰(ÄIi·áĂEđ®6·kÿ}ÎƯQdb¹‹•¦yµai7öË+·Ü1„-U|‘ûU¿).:ö +̃T˜eƒ̉”ßaQ +y¾hÉ,Li (‡byäôï'L+u E*ªøE­̃¤QđÑ€O2€R¼D®7₫m-s±|ÄđđåS~3€Ê|Œ`̣¤´+ơ|9́ C¾ÈK²?Ç@Í©I_ÛË!8§¦¦V‹l̀Pç;O•P+mf9ÜÂvŒ̣“ÔZ’ă0¯×oËá#"}hR§‡‘*)–µKÛ­­r«- ‚6Bi-Bc/G WƠZ ­\R«Ÿ]&%øÔ z<ÉtÇÍ-Ô°]°Ö£´ṕ )O°äÎÚ`r·®E\]Ü·.…Í‚‹Jùµâié«Ư5ª­í)‚µUP£;)Ú2:q̉AHèßHíÍá|iË„ta¡ë´5°B´¯æöRȶOºvêW[ÁÓµ9BÆÀ#P¯L-—ˆ|½4¾¥%¢ÁVˆ ›œƯV¤B¯'VLwªÔ‘ø’ -GkÛÓ‡•ưăŒEèüƯ¶‰¤8—ü@ `Ẳ¿Åzƒøä·\Èn,âèơÛó¢uàŒ¥Ié\Çă‚ᙆ¹ =!êÀ(oLè{À±å†ÀÁ>¸NÉmSc(ưZ¥éå"ß¼Ï~<9==z'BƠÔ’x2O‹uûÈ…2ơ®|åà˜~ƒ[„Gé2½çHđy”^aH=íä ó̉Ø@ÏGÉ ̉ ‘̉?äf‹í[ Đ4H;´efp₫¬} Ëüé-T{¾l‹$|ÇqjÛnñä̉‚džøáÚ»•JèĐ¿¢ˆƒ6q1äô¥ ÓÂñWOûp?|”ÿ§F–V9₫ Óđ‚+ư—–\-fë$́mjđ@±>–l#á¯Ưâ÷^ÇHv82¾₫¾/X÷¶zvÁÏ»¹RûÇ æË>¶âQ†{­kíÜN{rụ́Í{´ˆÿrúâüäÍ©Üo¸†Àó0°w¹èJf† ̀|ï­z—ø¸ă e ă!ù¯¨åª•ˆsØU$r¶yøÛŸL4"úS~’’ ó$i ¬Îq̉•%ÄaqŒ2U7ó°µ¼Œ…ëÖEâçXÀ²–$Ú]Ñ8U?¥ªâ¦ƒU]’vt™˜W^B†ÄÀn»0kr’¹bè%Yèg8z£+®\1&ųkœV6̉¬̀ûä!2'b>Ñe¾¬¤¹—0¤¹7¼n: FµpUƒ#`rûѸ$"h%[q́m̀W’û‡½ñó½1,gŸêă×Ơ4† #êv1¾ #¦”Œcؼ!î—₫`üœ€±];=.Qwµƒ9?΀=đe` sÿ§¤¬Àq÷å·“= ³$,r'Ê,ÄaÚ¿5‹Ó µ†-́ ễï=~èöÚmE4FÆyç¨íµ̉ÿ=z÷F¼=|ùΟ ÿkÇçˆC[ŒP¡ÙH 3¹¿ĂdÑâ‰8Ơû̉C=! 0§’ʯ¦Óm8cC˜ÔȰi×2ê4Ï÷¤kUz“r$%»ÆĐ6¥ Y)­oÙñoÜÄÛ³—¢U-v¶‹âÎ0µ(’Iƒ9(ÖÍÖÈs­ÁW ]µÉ•¤̃6‚iƠέл£×o₫”îơÑá©8~÷æµ8;ùñôđg^.ÙE›4gi'a…zlTh.%cv‘ƒRăm©6øTM² a¡³…îHz AÁ•ú$3ôVS1Ö¬Èdä’`1)fCh@3§ ¤~˜³„W°Ÿ”¸=å:¾JˆPq,ă˜^’ç‡ïN“oNÅ‹7§Ç'/±uœëèH₫gôÎJß…(_RG:OT `ÎE‡%L‹÷èå-ûö̉t>å%-ÏƯ" àÀủ@>,pĐ“®øÀɃlKC3•QD₫†Ñh$‰\w.‡Á:gƬ̉º!Ÿz[ ¥}çƯ†~pÁ ga¹µ¨t衜¢;æø”<™‡¹eyñæơÛĂó“ç'?Ÿ€û₫äü•UœÙ…_¹ów Âh+⬱$Ä̉ÆÍs"C3 ?n!Lk¤ëRæLSæÍƒ´Ơ‹øâ}üußr̃{È‚~æb…PHï·u<éÖ†Y(b,0Y¢Z«R‚€û4 %Ny ¹gµ:hçiÏ<ñq¥‰†̀x Đ‰ß0d9[ĂÛo‹cô¯û „1ˆư—Úkø3P`kxaè3µO¼[Û&˜+„B"‰Ä/¡Ñj_ÊøÇƯ6‰ç µV„m†T•èäcÿÈgRÅ `,xx-‰Kù 1`©/aYÙÍé#ˆU \³5ÖƒAFø¤]"¿œ₫xDwo¬̀Ñ´q*Eµ3Oæà¯Ê¬¢å)Dú¾ÿô+#ă™¼?|lÛ« H»“ÏVAív»̣a;ùÈáFf•›’~% ®cÑbkÜèHŒØl3Ÿ–º‡½xÅđÀè¸Iï98Ă-̀²êí,Ưä[¡*üí»£œ¼ùå¬đÆbYọ́'̀*ˆà¬A2́v%ÿ oêüuñjªå+¬*­&êÎ#ĐÑs@₫̣A_Ú”ÉK%&לYZ*–Ï+ô?¡cÿ X˜‰{sIÚÛ,p Ôç8ÍüÈ@ºW,̉ºÈ¶‰{ËăücTTB5he#ư¿U`oÓ˾wàåc]²n•yÏx7¨²¸§₫Mö6¾Ø[&¿́…U—÷«CÁß¶gå‚r¤Î«H‰Rü%@ÊqĐnÅF2) :f\©foé¸ÓÀ¥’¸ÇZohöAËQ6“T‡ó_Èï̉óÔx–é5P2´̃÷sY LÊ›ˆïáođ‰Ơ—4A C#´´Ùè:o*gd·{̃W¹µWÍ•¨ØáơH¨«ye‘Ë]u—?¼ï.Ûµu›ư+ÙË5DQ(Oçöí(ö’ÔÖønZÙ”;.6å6QùØœû­{ÙU9LŸG¾ D&«í6²v4¸¡‘ÇÁí¤ÁñAÎ0Øm:ÈNz”_ÔÖë 'w¶z)èÉÀ)Ø5̃ /”'N®xk`° g+c]C±ƒ·8Ç1x*¯+‡óq‹#¬›‘Ä̃(ĂˆF)7ú>ü¥ÓĐB®8›‰G½Î£}ƒ‹ÁGñ´¡Ô«W]ñw.7&‡å‡]qîϯâ0½bƯ[Ưz̃ÿđ1l4”y“ùHB!£ö)̃vÅqˆio‰"i¹§œ́*ÁvÆ6Â.ÉS^BzGJå¯Đd#êáe4bú•Ï®huŒ^xÓaŒá ưÁÆIÈĂB3"i ›đœIù¸¿ß}´}~úí<ô1'xq‚:m|ăê r)ê ÊJ;¦’=ô Ï}8æ¿In£O¼gùvŒWêơlüæqăIî@•]ªr²RÎ:O5M„²̀>³Đ)svtU[§°¯˜¤Ư<ºV¯ÑLăŸđ₫Î{/D#º7ÇˆÄ ÜǶØU¨ƒĂiËJqVPM!t€¹Eº ‹àØyÆAZ.S.‹H*ỹse[e­Q?!bI\Cki£Kt•S„JUe*_đU‡Ư¢6l1°Áʰ«ù}7¨ ›s̉Û•Z›«K?›•‰e.W+¶™œßG¥Ø¯" ₫B±ư#}ÛB±V$X#Ub¿…±'µ¦0lA¸ù£,́yÿy¿Ï™€Ÿ¯«6&ê&«ƠÆ4Z̀îjcf“e}?у0Y£ç'AÜ̃đ`,-ú–~£%ÓÖ ÙæG¥µ X—´é‘4gîÆAÆ`®Z³Ôó£’65°b5ëÚ#î‹«—¡«L°Ö₫7çf£Q Z{Î~¿­½arr9–û}aî]ëôkø mÅqíù}=Ưyí97ڟμE‡̃/̀FïÚ(Ù®·h¾û•ăºÙº6Êvµ[ôƠưÆ×¢Áv¹6>wµP[´̀ư=/TcpmTïj ·è†ûº†M6¹µbW+¼E£ÛU땃JµB‡Î® öÎfMtm­ÑFwEia+]©+}}u/£­T(-µË{®É¨vSJzË~á¹ê[QiØÇ ¾ ôĐgöWÓgÊo—ZÍúf¥a¢… W¿ÛÖ½«+\¹l¯qYàv¡r妸ŸnBss[j¶xÇ&Nv…è$ËùL(éM\=—ɇ; Ng0”;L‹};V?_˜ƒ /0 [ÛT¾ä¥—$Aºd›D₫ö5vjá5 lÖÄ́×Â\ï|ËfØ('/ßQ yôélmâWÁˆÿÚ ©Íj₫à;Đ₫w‡Ôôv |?i« uø• ́s è*B-QÖëEÊ*3KË…"*z?Uí-%XÂÛe5N“]ŒĐP;uT°€IRÖn,SÅI7½ÈTÄÉÊ|âû¾‰V=ªø¡1¥̣d¥´4O§v…å¶&*ºöØñzKAEÅ*ằô×ÁÆ¢y–ya¸„í‹Âưë32ư¢æ8™¹KV¦§û¥x™ăN讂¾CnÖ ›dgzæ;ÅëÚđÚGÓSo–¥2ØM´…?xÚWÉÓäF!¶vå©roĂÔâKØ+Ë­÷…¾s Ff€7À°0/3¹;g[f^Íœ‚·‰$ûE…«øf´$W©ß} ø¶uv ƒmbû!¤Ứ=ÓƯo ƒ¡#Ư£QvgăIÛÑ‹.^MçPŒæI‚¢¦]f‚ú†Í)­ˆÊ ¥&$¥ÜiđYƶ'>÷’M/ƒ™në3ô=ô©4Đ˜²“:T(H¯…‘·I<êR¾·+öïóü÷÷töïäÛÂé̃¾ "+đ™[q¨ˆnY¢Æµƒăú÷@kÚé»8qO܃Ӕ¶f|¸Ú›¶©ƯÈûÖU[<Å?Åạ̈"hZĂªfåT—z¤ù<Ăù\¶ú{86̀Êă¿{ÿjyÙ̃ ×®.:ÏÀ½Á‚Y Å¨êmÓµƒÄ”.s„¬$+ơR•ß䬭³!NctB«n~Döƒ@—¤8á@ơª—n1‘Œ[&ÑW‘¬¼B); ©€®¬ÊëÀç›`u\‰̣`/¹ƯHkH3UD—2¬‚£«Ë26øíÅm=¿»j́™5*×X€w Ú4‹²& †ö|w…Ș wƒÈ­,„ö„›‘¢8g닇…‰£OT¥Oz§Bú¤uỮ ûFÀÀƯú¢#úƯÇûĶ7|ư=|5xL_Ưç¯r̀¹ƒIÀtư¡~¤×ííøƯ|¦_SMØkxy ¹*ÊZÁ³̃øCæ)ë•Öb)åg¦÷ks¨®tmÉÈÔ‡^C,Vó3k!‚Bê(ÍÜ£j³dZíS±xy¯û PAĂè±gô Î"}̀¨đ)f/_—¿%qĐ*[1@RA,>ô?>ɉ{$Ëa欪?T±m¨U!Œy˜x\q|<ç̀fˆƠØ"ÿ" .(uÆ”ó“Äê†À¥’~ôÆ0س§â•Ÿ„óIvæWO1ấàQ[¿_¸J̉5Öe%YÆT ‘¾<>Çh4G¶¼‡Áµ̃b‰Ÿ]‰øy2ÇÙ0§â§ß<8Sç₫è2¢̣@¬ˆÓ¸»¿µ p!kË.‘„ºqu₫o@oÏư¬]đ~3³»æüfV²+ v\¿IdUY4¶Băê SĂY6`EvuæÄ„‘UV68©‘·¿Àè́æQ9`„S²ÔÍ_öà>ÅeO“¼K̉ónÊ×ôÜ<[;zû~¡“/„ÄôaÑ–wï¦ư¯Á̃@«>x·„X.ßùt²&,á¡?L…Ơ÷é=köˆ.Í]TƹfKVêÆÚØ{–¦à˜IœdX nbùZtëLËÊÍäè’(¨ˆ«ö̀Nú{|³SuwÉĐÂÉ! rû"m7Cg—kZ…ºqM:Û–¥`íŒÎ~ Ë̀ªy:»#íªId5Jg´k¼®N`“Ư&©®³rVQƯơi®§úl€Œ>'Ÿü oK’Ư©"»đaÚ̃–Pa ù²ˆ₫À»V§P s{ê„pvA™x6wM•x6R$¹jÔ‚°̣đ›GÛ,;M£m+›O²§»,ÿGỘWáU*ÙăßiÆV¿¥S ĐSô}ô§^ÿ|øö^ø¡PxÛf¹ª—Œƒ£©˜́%–’É|úÖ9ûP–qº¾ôµ¬ÎëÜí¹CÚ¿Ssºk§fÔ(ñ–@wÀơCS…Ó-pØ₫A[×îál´AX2ă'ơaÔĐˆè]«Djä¦EaX¹ư]ñf6ó£K?˜²iƠïºâ}Wœ.½ VtcÚû2HGÀ2üÎ9θ=†`ˆ€ª¸7À₫A4çÔUBuSeEe*¸ˆ'w*gâæY°ĂHƒ!¶[ƒVOG¤ÿN²V¿Óܻٛ¶»ÿ`¸Á6{&–Eđ+Äô‘ïẤé3ĐCø_ø¦‹Pxyµoc‡wœŒ·&û&”yéXaÏ«“₫ö,À@Û°çw׬ÀY£́À¼–Đ,ÊP‡́ùî ‘;PvƒÈ­${»Ḷ4îkG¨\™?T¨¯P…ZG™î̀ùŒáíû©xÉg•BûBߺFO½®* Ø.Ø•5¹»æVÖ¼¡ o ̃·–+#!.Û†÷Ơ«Wß„̣ö[P‚ÚÅÔÓºëí§çô¥SfÖ¤ˆ”ècµ²oÊv“a/­‹eûđàûÖ(̣*á6Pà• í¤¸«œÓ]ïA5£f́ mƯ-(~‰°™9V•‰´’_!(\± {_Ä(Pïî/°pqNè‘­Đăñ¸vD ^ºÜú)ÅrPV‰4l×Cß‹†&{^«ø7œ]›^!Le£Ư'ÉæW₫í ¬ä¡Pw®qˆ5́±„µ“ƒ¬gvçGYϪÙ ́.ª07ˆ¬ªj”[¡q‰-vE’xà5láÉWQ|a;:·£8½±“y32%̣íƠŒ¶u3–ʨLÍBû¬£“²26k¦ ,dºƒ:sᾈR—à-'~±›•oàôè¾Tç´?Ê´́N$UÍxÓrµÏc©gA0z2Der^NUJ¡z³÷y´Wa~¶—’­ÏÔbê– Ă´ÿ̃lpi·x#[×sĐ0'²«nœÆ°x–%~S|Cê?>¸5²ë¸cøñÄ›á­Égk 2™RẈqp\>”–ÁTØ2?<Ùtºâđ ´?à’GữA§ß?PCÙ›‡ëF+È"`Ơó¤æ(+˜h„ºsu½½‘FÁÚ…Eß̀́®-úfV*á,úM"«‰8:3×Ư p1t»@áVtf²xD¸‘ÓÚ±é¹ÇTFÛƠie­¨ư¬ßiE{§~û_@b…ˆ}è¹,Q×¾¯Óÿ(Úr(éçîU#V;z2ăh£ å9•›¹äµ=,Ơ}!ß‹̣jûàÀ—ÎUyL¦½OƒñË­HuØQˆÎA…ú¶`z‘ø.öéÂÉӨ规¹ˆ£\Ê¡)¯Váç®Ư’TI Ÿ*Dó.Ô¯¡6ä(üÅså—º…pç€è)VZJ×QNølç±PÅŒÇåø\¢ cNeư5QVÂXUd@Ư,ØÚ4~±)‘€–g™@đX.ă ۀ0@wØlacTÈØ‚¢OêMŒÉIͲEÚ¸Çå+Ç|UƒÍY¶Q§S…Á¥œöÑ#$QµÔ f*ç¹ÊÆ̉úºy<úe₫:QÆ\²=•‰KUŒàÿ( ¤¨˜­ïVxăqÀ́Ơ1­ç+ñ(߆f¬-ƥɌ*lWáj®ăµ±́œŒáàø\NwA/ÇÊûeCÇà«"uơ®5ƒY¯µ£— çÉâèÊA·/ø¶Ơɶ»=ÙfHwág¯·}ª½rµº÷O¡p ’SßEv‡₫F”E¡·Q‚/̃‹ưw²fWGI€†*$¯ê yĂ/TEå*ן7ÏâÄ¿ bÙ  ¶ßµ±[¨O)LX6 ôa'x™W檛¯ñ\_„(ô ­ÉÁÈïH]»ô"Èç0hêå{ĐVúªÂ,Ăøíh>†h~íxp˜$0öX$₫x>̣+‡V;< Å ÿJæ6£ÊjdøMæ:ËùđơÚH¨¦ÈÚ̃¬.¤ƒñ́¶ ¢©WÁ½ä×Y:–‹í˜‚ש,v½h€–̃ôîÇ_^Ÿ±'f%cp®Y™m,WZÙCígGDóé† #¤¯•Æ£q‰N¼`èd²̉ưTA¡ *"² gf–Àv³'¡n€…ÇJ'ơCï¨o€…úG—V-Ù+Îæpó"ÁÁdÏpv.ƒ@<èéJvöÏx®Jụ­ơƠ U¿…'®1ÈÜ+p3ÔÑYÖ!«&>,a¡B 4 9:Ư“u‘bJ Íwhg¾ ëK?œÚ²Ȫê!DkĐ'<¬qI:‘Q4>¬© <Ñ>mi­Er/i….TêÑe§> ôC£…c äÔKA©iMùÇñ}#z’‘‰¨È  E{%zÄ5ôåYÁw5[’kˆhƒ-2®¢â 00/·n܇÷Ư 8êđ á£ï9ÊŸ̀ u3 <öZqfpT9]¹Ó¼O^âL%œ"éî÷Ûâ0/c’»J²“¼yŒY&L%•o"ÑÏÅ]†à̉X·ñ¼;WØhø‘xs*Î~>zq~Ÿ^¼;9?zŸ̀y~ă ä[®<ĐÈ!vè¡É!r¬æê Ky·‚êàLg³$¼ĐĂ@Ÿ ÙZ( ‘¹r½ /ˆÅ—¸ư0Tû¯N”p"â¡!ÇĐƠqĐyv$ ,#g¼ w~ö±8:0ôƠ_ÈŸ\LÄ!á"¢M*ĂÆÙJ̃NĐq,]18S”O#AK~´U’}(já Ư•*’F(]D<|Œ±¢¿Đëôï÷cîÈ'|è›aïïƒ0 ¼©xƠ¥ˆ‹Të€lsØç₫ü*Ó+ºơ¼+₫áĂNIBªÇ‹́ú9&U·]¬ëE~rkf{ 6‡}Àî f¬XÀ1Ej…5ơa")1H4ˆÉ̃>ºˆ“+0 Ÿ-Œ„ƒ̃t˜c 2&&…çAa'ñƯ”qy&©W¿ûÈZ·ûÅápÜù) ¦p˰/böÚ >{â¹Ú·½]¹Ÿ¬}ÍG¹B€4äEGơjŸ_s8Ơ q 9ŒÄ“Ñ0U›™&OiA­₫ M‹½¿ß¿ßÙßÇíùăw0îfß«°[{”¼ävÎ2äËä@đmëX&l–I„t%oe·†BÆńU›Y¢I Û èïÁ¾ø•®×rOÓq€R+tÊcRoî0#ÎùOû̃ ‘•k©D s 3Ÿ½ZƒTn¤V°|‡b‡‚lˆO5(¯LÅÖ°–øTâz₫‘Uc  Q£—ºªU§÷YM ̣¥ư"¸*œ¶ÚhL{$ ›L†ä°ßnƨ…Ó¢9b†»ÁK@[³6Å“â‚܇«q€r^xË«̀´¿å¹ŸÜn·ku…Đ|BĂty`.5fø rûtöÙ˜g°Đú„BlGù¸Í¼R«ôûQÏd%ȉû“{=ª#¶?<¡d\å­$••r[ ä:R2äăÁï ;̣}Ÿˆ7 ˆQ0F9ŒYöÁ\ë`Ö‹²f O&ië˜g„Ë36©T…ác:đå--ÀĂKYs„M/GÔ _JA$pÑÜ0ºâzWù×¢*R@ ˜?Ư„N­ô‰ĥ×)+̣I§2j‹”+­×nÍîƒèn„%ü~_ÈûVgøđö_‚ú$ĂƒWø{tL¿£çüÏ!₫ó¸q®ôÜ=\…™Èѵ^¹ÇnôÜÛ±¬FûW›^£œ|¥W̃/ÇëQé¾ß 2å̀¾JGđëÁ«₫œúå¨w?|Äÿh8;\†•±ñÅ– µCú ăëZ!™ £Úư"-ÀÁJ2«deÏ[ŸÛ{‡đ eç­ÿHÛl¹b¿¶éÅ©Nẹ̀Éëk ¤Jű®ªÿsÅĂ\ëâ‚{º;"âg¢çEëÚfŒ 8u¤Ư[Jjœd‚®ÀÔV.;‘<2å}W‚ææS^áOçø©Xf²±ú¥)Ûƒr¢QoES›̀l±¾í³}ÛX•-Á›ºÅ[¨ÿäè2N)d[ùÙ`̣G •dsüYăƒ́sçơèy‚=Çq x*Ơ' ă@xÛ6cË)₫ê ¶Đ~\¿Æl‹:!ǵ[Đ»¤<´`mAB»$Ư+A–A¿“*W´,óD©(°đæ²ặ‰7ÅÁ¦ÑáÙ°{X[;êĐÜưܺ;BYñ̃çú^Zîg……x"ÑN„Èb$#q[jé:lFe)ÚŸ;¼aÆ”Ơ®†›æá₫v-¼@ ₫´̀Î)@Nk ¿âœX-Ç+´!.ù0WUu>?_¡µ‹ó`?_=óof-̣vúí{ǺÍúJ¼ˆ̃ ô¡çv|”ÎÜ j9œ4'£È¿ µ¤]̉A¤*\éE]Íe* 8ê,€•Vàö÷î·Ỵ̈˜?¼r¯ñ"i[-¸ÓíôÅç—îá%^¶‰û}W?ưể<·ªïa“:g `z̉úëÿüOÅJÑúŸÿçÿ2ù«‹™Ö­WW—í6À°±́P‚Ô8₫̃ưÿÛ»₫ç´‘dÿ;ÅÔÛª²XlÇ›øùƠË&ñ%{Éf/qvëUÊ• ŒÎIØ&?Üß₫º{z¾$$p¸Wïê6! µfzFÓŸéé₫´øàˆOXŒTâÊ¥̣óËưđ+Nª»ÓSÉM1’́`NGJÊ ë‹Ù,P_đzù§˜,÷ÇØyå ñlCWûŒṇ̃1§Q&<¶ÉW-Z~ä¶øm³¹û́—#ØêâAÖIç ^Ó¶îØ8IfÏF'f 7œ₫ëŸa|ÈÛD¬ûơWôUM__£N¿¾§À)gœL‚v_qÁöëXÍxăưW\ă,̃ïX\y VÔÁ] Đ‚g₫°MX\Ă.¬\ß~˜VWA-₫q Ön@ÈötTo0₫cjØă]E9løăó*¿æ¿Aô ¿oÔô Î7B6Bø9¿±„đ—¼‘® ×svØa¡g²!0¶À¬ùµ©’â”éD9Ø9¼ieCY™¹ œå̀uö/^+]äµ́bÈKÀ\8_º‡=ѽ:SçÙ/è;û›;»¢g–…Ád1Æ Ư™V྘wín»kƯ<6wăƠöưè«õµ¿¸}¸±uF[W:N.@ú—aóñ‡€̀ÈÇíÇï¹tóc#æ&<Â8ưC¾ëÑ5é­N 2„Ï+ °:†ù^€aN”¿oŒa¾×ˆa¾ï7†ù^ĂupÖ¶à™? Ă|¯Ă”ëÛÓê¾b˜ï»À05jd+§åÇ0›¹'÷ ¼®7Çtp÷?ó[ÿh2}IÇK®¤‹”+i¯ÜH|à,\ÏkÔs uayaDWGJÖ¾&ÅÂl*eTY!ÊŒ¶ v2¬Ơlj±ơ¨={AàÏÎ^³u˜å'§~挈Wó¨ïÕñ­`@‹~2ñkÜz ỵ̈fxRÔ„V7»Ïg­–x"î‘)¿è=ŸưÜm1‹N[ø̉m‹{vÓ_)L{AçTØ€ ¤¶²̣ê,×q,mï9bvU¸Ê{2Ès´(,>àŒ? ­3Æ₫¡±t‡¹aD¨×±f ú4S§g”£&ª¡uĐ…_%%J¸çé/w7#Ô‡̉GnÏ…Ư¦S8êÜJ‘J8UU…ÀD€+óBÛÎWpG*IưÏG›…6•d¥Æå3%e¡…á±¶KǺ¯¶Ckô®sS₫Íâñ«X½Ù Àà ¸f[‡k0s³Á^W“ªGên¸\¢êµN q÷T<®ÖÚ́ª§v…?@‘‚|¤v½Ûl0Ù\Åơ@‰µØ?Ä|/(€Öñ•bxsƯ Ñ™üÀœGÖ¾¿p•?ñ¿«Üäåû†â‚ù¤6Ä"ö¦ÈĂQ̣IïA*­€ÇÁ~ö—Ë.g)¶¯”ß`Ôf•<Êc !̃;ă`μS„ú5–”¼A:€½;yÀö+ÎÊeuY®2Ä€zÉÅC‡¼_1ƯY½µ4ư|Q^«?_i®·ù½CMaú¸båÈ¬È 5w#¥»&BÁú±ŒJSabÅă%Ăä‰i¼O„ nù÷”"¬˜íѳ€́™ØL¦²öơ5̀lù(&‡‡/F¢°½“Ù|¥åkOi’Ö\1D˜ÙAœhÖÓÂQ.qÎ̃]'máh“­Î"^~ï̀Óy—âg¸¥Ÿ¾ĩæF´Ơ¯FÖ5é¥ú*eäÂçÿb'YzfàÔF¢qƯcT3Aư0 ©3tH—k›‘ĐÈñ!fđ.é¢Ô¹”„(®(Ÿđ¨=.zˆÍVm»ưh,G=™%̣đ‘ >äRFŸæö¬N̉́Îâ§FƹFËeBO”´:è—ơ‚TÚ(±¥¬khC²n#–ÄTEâßC›,Wm2ˆ{@÷œ€NYâÍ™l˜"ø½#ø¨ˆ·ơô3œ2Ä&äLX…†<¦!ư0NW¶a{ó'•|+ÖL«KXwqôÓ둦d(]^¥Đ±…´TêïfÈÅUÎázº§'Ô…@-ºˆĂ²À»¸(í3*Ù‰oàÛVS+ª^Ü¢Äî̃ ¹oúÏøe+‚W£ÂƯŒLí₫ʃ/å ,ÛÔ81ú(á! ï¦̀ëcæú&ú *©8œó‰«Â=̣¦#^€5HvƠ+ß |7¶Đzc6‹¡Bç6̀"_²cĐă”_N9¿d¤`»Ü$Œ¼ŒWÉ›®Â”gĂo­V ¥ œå¦ưC:k¯-¬̉(ø«ÅơVb¢Ơº+†qi´ƠÜR…aÊt́âíG}˜Èáâq®n å9ê §aQ7éÙéđ& Ọ̈Æ:«: 1Q•+ù ˜;Ù©9è§ŸÄßùA§yIÊÛÄ0ëÎ]H $klc?c˜›€¡ơ ª 2xB÷.ü6÷7æ"u@¶¶†t!Ö:$ăAçH­#ă%í•iĐ₫°½ñu(%Ơœ@CB÷É<„æë2ƠJ}»“}̣püØ1Éøå¯A…á*á+ù<[ơ”ÜK—ˆq„|kó™̃³÷|{2ư¹‹[tÅIè˜̉́âÛÆÛf1M…MKêAêËs²²¿^·½̃ªâEƆ÷vçzg'îÏi[»º^öt°¥{¬7s[?ƒ¢26qrD÷´Åâx›ûV Sr0wXx°ù‡Ï÷äØÈư™̃ï=¡­™̃́•Øëe X, ˆÎ̃ZÇŒZˆuïñ̉ăS÷÷Ï>©•2ö†™å>¶ DTF JPf8ÑO,Œèê¸AÉzˆPüă₫qù裮]ÆWÖ…8ŒzkµoŹ>¡=2ùójË1+B"M !£±‹¸jÜú35'ÜÍĂü#q‰¦ÎÇ’d^„FƯS¥œ`Ơ+<LËéüÉlÄI¶̀S–$(Îñ¤ú0ĐñaÈ¡üN²º1±4V₫ Osi[v·̃À,göGoD©8¿9âoX^"to|Y`â}ó̃‚Ù€ïÚ M¶Rêà9|†}³1:mñBơ<–Ñ-ú/”rŒ;Ơ¡ÓÆS"M~ăƠ‚8u0fp戧éöơ®°̉ÅŸø€±cÏŸ´ÅGÉ?Ø1!t¾üu>¸¡¶¦˜ơÔ!.Π:a¾â*&p¯jØlX÷Ù³gU­ïˆ ŒÑSµs.o‹´àꦈEX¢w¡;¤ÂëjqÛùº¦u²“emüP¦H«·pUSȽm“ÑœÅYn\b+i‹YY #j?Î&ó²>Œ¤dí•wŨdÜîFQµ¢-vŸĐÎĂè¿V‡»Ñcé% ål÷§È’‰¦*¯¹]:²aÜỹ”}ÆÊơ¾ÖưœJÀQxƠä÷{7¶€Á˜Qpàĺ§ó„°sˆQäư©DAư Üd"5@=®æÂ6‹êwv}É ›rô%KB²́TS]¤[TT}ÑZÙSr~ŸOú2ÊÛ´/Ín§£ˆ[ẺmËÿÉR$3à|‘׫J9H  kˆ¨GZÅv&«Ê÷9E-±Pª%=Å´8®¦ÏfQ…úÙ >I9øSæƠ…óËƯȽ²¯ḲÿzyuÉiÈ}₫ùr‹Ñ¶WT̃Ñr¨®ÇÔVhµœ«……<—W¼”ä7Z èvqUĐ¥µ1GV#ùp/gjçíHLCT́LQŸ"t8Ÿ5LJï\À“=²~< Üó­`»́¤Å®‚ωøÉb“€¯`÷À‰à—w èGlæèÏG#/ÂÇ®ñœ8]!/,ï 0‚«ûXÖî±tyÇ¥RÇ»-óO3ÂÙṼL¥ÚZ? }¬œ ñ½XSeàØæă¼ÆP*+„¿̉…&ÙÈŸ&¡âZÁêæÉLxƯ" ̀ʈœVưâTôÈÛ̀¾d˜ÖŒ ‘É':ƒ5°"GØTĂ8éøá|à å³äSuñl̉'´W*²̣Úi•×ÄĐs™ÿWܸYFă^˜ ¹À‹1²ÜÍ ©Pm™Æ₫s†°ÑIxëE;kh_¿¢W’]V6Ü£5‘¨‹Nqïô»êß[f ÀIêÊÍ\÷6)6sbp-^nO·Ê³ ÚJ‡˜ñ€T¶)̀L0È ³e昇Óy‡|"35H¶´5ùJBĂå˺‚¹¶@¡…ü­‚2@v¬hJ²)$R-+êœi178x*ĂÂ0Ä*‰µè̃Â,=ÎSf—Eăœ:ª&o‡'2–›UVư^Ib¦ï˜AŸäªE‡I>ÆÎèV[ègĂPƒåj)ͤ’~w¹¯é$ñ…É œÑy<×́S j¿¬— „wDˆ¯Ë{Ùøù]ÄèŸëÀc̀«×ù,¦¥ ˜́ßfX2~I ʕÈí~N?{-°,¶øDˆȬ K浟½:ÓNKQP²@,Đm’u›ª€€ûĂ—£6IöBˆ±ếœ«Nü„Hl“Tjxd¼˜f:Y_âÉxè7²µä“Oa×8̀ ÀËpÏx³8ÅùjÑăŸå»Âè œÀ?â9%J¿_Ü–§ôj̉‘ÆÇ耇†ưÀÖnǺ8fæ¸Ă–Ăª·hÖđÊxÙ¶îñ`«ó«Ç^ ̉ÙDÁÅD|§\ÅZ‡²h(dÑ Ÿ̃<öFó • èQ)°ç¬ÅXv‰J¤]Ü?t.Z̀µ¾ÄGœ/C€SÑK¸%ï£séˆOă0J”Lù^éú%¿ë—B¼û²Œ ̉û€đ˜¹ˆ 'âO,­Q¿»»s( “¼a¼ÀLûØ=œÍû:²̣sáÀH ©¡¯,¥,áƠÑ”öxê¢´í°´RÁzäWoLr¹èlc",-nàë“gŸ|§ôư,Ók/3Æë‹́ß3·7±%r©‘‡8nv”Óm>ơoñeHVÝóÔ&·*ª‚¡âç¾–ïm¾âxÓd€E¸OJ›„,UñoåGd]™ c3[b'‘²÷øG-ÆÑ|€d¯’X¹°î¿L¯Ô¤Â•Ơ•„ƯĂKu ±b €e×·_¥»ŸŒ}¹ÚËÓdh läS$c;øÉøÄ3‰§éB: Ñ[ø¹sE«0`ÇîSÙaoééKÈZœ¨̉rú0KvWéVĂpO5—c p2DÈQT–¶dÁalôÙ'”Rª¿úƒqù×ïû©àë6xÉ•àêoö×N§÷Ë=₫9núDÀßGĂ.₫ëÙÚ×|å%¸U¯l¹w^÷¼àưÎwA¯†Bßy?AÇäOçƯ–^ʽ§…jªƠcCOûÚëôÁêYÍmnÿ§¦gÍăcEAn®WÓÓB|üV•¸¦CÈyøüFŒÑ!°¹¢DøTv¯.Ơz¤‘4̃‹·̉¥„Œóä±́ĐŸÈê:ê·w ¿rƒ¼ƒkƒ%̃&ä ’©ÂpYTp w#ëJ3Ûµ£€MqÍŘ/3¢iẫ‹Ơ—JKkéP—5A7·Æ DÉMßñ́yM¡ÊS™-Aø¹YKĐ‹Âäós’)Ág6¸î£~¦ øí6{ȶÉf„*&|é:GpÍÓ+ÜÏah~¹ ú§üS~¢>Ö(”·—̀QR=;‰¸Ưf™VØN¤Hô>±l;kj«‚•Ơ_!Êd/È’Àsoq+K rØüˆöt±¾ƒ£ —âí̉±r*–=³ ÜƠ5(I‰.™O[*_½t~·â:‰tưM²{¹Í´4†”Đ`,%ăVP3î[ƒ§±×‘7ó² L©G "~ÿ«=sDÓ[€­îµ¨0y2¢Qt–K«¼Úf}̀yÊ—ƒ® ÿ_e=~ÿÖ|´´öÚêÎØÚjQÜƯx̃úR'Î3AW•·~,´ºÙ#A{eïX;1t[Z°jµpRæ>™¶P{}ÉĬ¾bŒûC,K[³Ÿ×鯕¡ôh>e„H$3{8»Ö¼êú.̣n‹Rå;¯Ú`Ñ ™5¬ g¿– RCơ©»á$$5ÎÁÈ…{&¬Iª¥ÜŒ<à´~ÊÛ°`Îù°MQå9‰©|ä đ§EG ]É,ª®.?GÓϨ>WmyqrØ)=iÓúÙɺ»ƠÆ"­±̉,D±60W:÷\̃Xh*¢Åù¢yßôyOCܸ÷TÖ•ÊjúSÏ–®o3÷e1̉( “Ơó4Ă}ù—ơBŒà₫iƯ;°Ó"£Ố7׌=wH÷B}%g>\}²|ơA?.̀088k/>|¸̣́ˆüÇO¯>¼¼€IÛÄS#Tÿø„´đ›#̃8÷ƒ—l+Ưi[\:éíÿpéü¶%ïˆÜ^|tû N°R |!84B:~â¨Ã+JÀ±`G5™OˆIü‰?¨>"ó¿5ît>ùÛׯ_‹ËÈÆx1ú¡xƠç¢Đ„ó8qÚÛ0€Ÿ>ô0ăÙéQ[̀f8é<}4ºñǿ¤wâÈáƯDG½”HÁî"¥£Kwæ‡O™úÈO‚³_«á‚ă‘–k,pƠ™¡»ˆ5đk¬§$¼%÷ĂđƠ×È-t ExCùø Fåïxï0Qe.λh‹ßÂñTüëÏ¢?~¢pÈß½;ñ?atCµXƯ“Ö_ïôÔi4Í»=¥›q’̀bxá v’yâŒüĂ%ñ!=₫«|¨3ÂâWúRTrkóñ:J׌×Qz¼@)ocÿÚk‹÷èä¾sqÀtY D ×Äcß ä /…¡|mغÀœ¾‡ñ¥Y,Çód… ©nOđâ9-Ósè@ÿ¥ æxZCă"#4Û ñ'ÎîăS¤Đ¡¢¾=*—KCÔéüÂcÔítOUđ¦Ü‹Â'Ô~3N&°$ư/ ÛÓ² al.html#Filtering3.4 Filtering(signal.html#filtfilt3.4.1 filtfilt$signal.html#filtic3.4.2 filtic(signal.html#medfilt13.4.3 medfilt1*signal.html#movingrms3.4.4 movingrms,signal.html#sgolayfilt 3.4.5 sgolayfilt&signal.html#sosfilt3.4.6 sosfilt6signal.html#Filter-Analysis&3.5 Filter Analysis,signal.html#filternorm 3.5.1 filternorm&signal.html#filtord3.5.2 filtord"signal.html#freqs3.5.3 freqs4signal.html#freqs_005fplot 3.5.4 freqs_plot signal.html#fwhm3.5.5 fwhm(signal.html#grpdelay3.5.6 grpdelay signal.html#impz3.5.7 impz*signal.html#isallpass3.5.8 isallpass,signal.html#ismaxphase 3.5.9 ismaxphase,signal.html#isminphase"3.5.10 isminphase(signal.html#isstable3.5.11 isstable$signal.html#phasez3.5.12 phasez$signal.html#zplane3.5.13 zplane:signal.html#Filter-Conversion*3.6 Filter Conversion(signal.html#residued3.6.1 residued(signal.html#residuez3.6.2 residuez$signal.html#sos2ss3.6.3 sos2ss$signal.html#sos2tf3.6.4 sos2tf$signal.html#sos2zp3.6.5 sos2zp"signal.html#ss2tf3.6.6 ss2tf"signal.html#ss2zp3.6.7 ss2zp$signal.html#tf2sos3.6.8 tf2sos"signal.html#tf2ss3.6.9 tf2ss"signal.html#tf2zp3.6.10 tf2zp$signal.html#zp2sos3.6.11 zp2sos"signal.html#zp2ss3.6.12 zp2ss"signal.html#zp2tf3.6.13 zp2tf:signal.html#IIR-Filter-Design*3.7 IIR Filter Design(signal.html#besselap3.7.1 besselap&signal.html#besself3.7.2 besself(signal.html#bilinear3.7.3 bilinear$signal.html#buttap3.7.4 buttap$signal.html#butter3.7.5 butter&signal.html#buttord3.7.6 buttord signal.html#cheb3.7.7 cheb&signal.html#cheb1ap3.7.8 cheb1ap(signal.html#cheb1ord3.7.9 cheb1ord&signal.html#cheb2ap3.7.10 cheb2ap(signal.html#cheb2ord3.7.11 cheb2ord$signal.html#cheby13.7.12 cheby1$signal.html#cheby23.7.13 cheby2"signal.html#ellip3.7.14 ellip&signal.html#ellipap3.7.15 ellipap(signal.html#ellipord3.7.16 ellipord"signal.html#firpm!3.7.17 firpm(signal.html#firpmord3.7.18 firpmord(signal.html#impinvar3.7.19 impinvar.signal.html#invimpinvar$3.7.20 invimpinvar$signal.html#ncauer3.7.21 ncauerFsignal.html#pei_005ftseng_005fnotch,3.7.22 pei_tseng_notch&signal.html#sftrans3.7.23 sftrans:signal.html#FIR-Filter-Design*3.8 FIR Filter Design"signal.html#cl2bp3.8.1 cl2bp signal.html#fir13.8.2 fir1 signal.html#fir23.8.3 fir2"signal.html#firls3.8.4 firls*signal.html#kaiserord3.8.5 kaiserord2signal.html#qp_005fkaiser3.8.6 qp_kaiser"signal.html#remez3.8.7 remez$signal.html#sgolay3.8.8 sgolay,signal.html#Transforms3.9 Transforms.signal.html#bitrevorder"3.9.1 bitrevorder"signal.html#cceps3.9.2 cceps(signal.html#cplxreal3.9.3 cplxrealsignal.html#czt3.9.4 cztsignal.html#dct3.9.5 dct signal.html#dct23.9.6 dct2$signal.html#dctmtx3.9.7 dctmtx$signal.html#dftmtx3.9.8 dftmtx2signal.html#digitrevorder&3.9.9 digitrevordersignal.html#dst3.9.10 dstsignal.html#dwt3.9.11 dwtsignal.html#fht3.9.12 fht signal.html#fwht3.9.13 fwht&signal.html#hilbert3.9.14 hilbert signal.html#idct3.9.15 idct"signal.html#idct23.9.16 idct2 signal.html#idst3.9.17 idst signal.html#ifht3.9.18 ifht"signal.html#ifwht3.9.19 ifwht"signal.html#rceps3.9.20 rcepsFsignal.html#Power-Spectrum-Analysis83.10 Power Spectrum Analysis<signal.html#g_t_005f_005fpower3.10.1 __power,signal.html#ar_005fpsd3.10.2 ar_psd$signal.html#cohere3.10.3 cohere signal.html#cpsd3.10.4 cpsdsignal.html#csd3.10.5 csd$signal.html#db2pow3.10.6 db2pow(signal.html#mscohere3.10.7 mscohere"signal.html#pburg3.10.8 pburg$signal.html#pow2db3.10.9 pow2db$signal.html#pwelch3.10.10 pwelch&signal.html#pyulear3.10.11 pyulearsignal.html#tfe3.10.12 tfe,signal.html#tfestimate$3.10.13 tfestimate8signal.html#Window-Functions*3.11 Window Functions.signal.html#barthannwin$3.11.1 barthannwin4signal.html#blackmanharris*3.11.2 blackmanharris6signal.html#blackmannuttall,3.11.3 blackmannuttall*signal.html#bohmanwin 3.11.4 bohmanwin$signal.html#boxcar3.11.5 boxcar&signal.html#chebwin3.11.6 chebwin,signal.html#flattopwin"3.11.7 flattopwin(signal.html#gaussian3.11.8 gaussian(signal.html#gausswin3.11.9 gausswin signal.html#hann3.11.10 hann$signal.html#kaiser3.11.11 kaiser,signal.html#nuttallwin$3.11.12 nuttallwin*signal.html#parzenwin"3.11.13 parzenwin&signal.html#rectwin3.11.14 rectwin$signal.html#triang3.11.15 triang(signal.html#tukeywin 3.11.16 tukeywin&signal.html#ultrwin3.11.17 ultrwin(signal.html#welchwin 3.11.18 welchwin$signal.html#window3.11.19 windowBsignal.html#System-Identification43.12 System Identification$signal.html#arburg3.12.1 arburg$signal.html#aryule3.12.2 aryule&signal.html#invfreq3.12.3 invfreq(signal.html#invfreqs3.12.4 invfreqs(signal.html#invfreqz3.12.5 invfreqz(signal.html#levinson3.12.6 levinsonsignal.html#lpc3.12.7 lpc<signal.html#Sample-Rate-Change.3.13 Sample Rate Change(signal.html#data2fun3.13.1 data2fun(signal.html#decimate3.13.2 decimate,signal.html#downsample"3.13.3 downsample$signal.html#interp3.13.4 interp(signal.html#resample3.13.5 resample&signal.html#upfirdn3.13.6 upfirdn(signal.html#upsample3.13.7 upsample2signal.html#Pulse-Metrics$3.14 Pulse Metrics.signal.html#statelevels$3.14.1 statelevels&signal.html#Utility3.15 Utility(signal.html#buffer-13.15.1 buffer4signal.html#clustersegment*3.15.2 clustersegment*signal.html#fracshift 3.15.3 fracshift&signal.html#marcumq3.15.4 marcumq*signal.html#primitive 3.15.5 primitive<signal.html#sampled2continuous23.15.6 sampled2continuous&signal.html#schtrig3.15.7 schtrig0signal.html#upsamplefill&3.15.8 upsamplefill"signal.html#wkeep3.15.9 wkeep signal.html#wrev3.15.10 wrev0signal.html#zerocrossing(3.15.11 zerocrossing œ\êÖ¼¨rZ@*öܦ~dN6 æ Ö º „ t b N 6 "  ø æ ̀ ¶ œ € b J ,  ̃ ̀ ²   „ f H .   è Î ¸ ¢ Œ x d N : &  ü è Î ¶ œ † p X F . üầ¶¢p\B(̣ª–„r^B"øØÄªxbL(øæÎ¼¨–„p\9 ÷çÑ·£w_N/羡qR7 ̣Ó¶†kR7  ̣Ù¾£ˆw\ data2fundata2fun lpclpc levinsonlevinson invfreqzinvfreqz invfreqsinvfreqs invfreqinvfreq aryulearyule arburgarburg windowwindow welchwinwelchwin ultrwinultrwin tukeywintukeywin triangtriang rectwinrectwin parzenwinparzenwin ! !nuttallwinnuttallwin  kaiserkaiser  hannhann  gausswingausswin  gaussiangaussian! !flattopwinflattopwin chebwinchebwin boxcarboxcar bohmanwinbohmanwin&+ +blackmannuttallblackmannuttall$) )blackmanharrisblackmanharris# #barthannwinbarthannwin! !tfestimatetfestimate tfetfe pyulearpyulear~ pwelchpwelch} pow2dbpow2db| pburgpburg{ mscoheremscoherez db2powdb2powy csdcsdx cpsdcpsdw coherecoherev !ar_psdar_005fpsd!u 1__powerg_t_005f_005fpowert rcepsrcepss ifwhtifwhtr ifhtifhtq idstidstp idct2idct2o idctidctn hilberthilbertm fwhtfwhtl fhtfhtk dwtdwtj dstdst"i' 'digitrevorderdigitrevorderh dftmtxdftmtxg dctmtxdctmtxf dct2dct2e dctdctd cztcztc cplxrealcplxrealb ccepsccepsa# #bitrevorderbitrevorder` sgolaysgolay_ remezremez^ 'qp_kaiserqp_005fkaiser] kaiserordkaiserord\ firlsfirls[ fir2fir2Z fir1fir1Y cl2bpcl2bpX sftranssftrans.W+ ;pei_tseng_notchpei_005ftseng_005fnotchV ncauerncauerU# #invimpinvarinvimpinvarT impinvarimpinvarS firpmordfirpmordR firpmfirpmQ ellipordellipordP ellipapellipapO ellipellipN cheby2cheby2M cheby1cheby1L cheb2ordcheb2ordK cheb2apcheb2apJ cheb1ordcheb1ordI cheb1apcheb1apH chebchebG buttordbuttordF butterbutterE buttapbuttapD bilinearbilinearC besselfbesselfB besselapbesselapA zp2tfzp2tf@ zp2sszp2ss? zp2soszp2sos> tf2zptf2zp= tf2sstf2ss< tf2sostf2sos; ss2zpss2zp: ss2tfss2tf9 sos2zpsos2zp8 sos2tfsos2tf7 sos2sssos2ss6 residuezresiduez5 residuedresidued4 zplanezplane3 phasezphasez2 isstableisstable1! !isminphaseisminphase0! !ismaxphaseismaxphase/ isallpassisallpass. impzimpz- grpdelaygrpdelay, fwhmfwhm +! )freqs_plotfreqs_005fplot* freqsfreqs) filtordfiltord(! !filternormfilternorm' sosfiltsosfilt&! !sgolayfiltsgolayfilt% movingrmsmovingrms$ medfilt1medfilt1# filticfiltic" filtfiltfiltfilt! xcovxcov  xcorr2xcorr2 xcorrxcorr wconvwconv convmtxconvmtx cconvcconv rssqrssq rmsrms peak2rmspeak2rms peak2peakpeak2peak findpeaksfindpeaks vcovco# #unshiftdataunshiftdata uencodeuencode udecodeudecode tripulstripuls squaresquare specgramspecgram&' /sigmoid_trainsigmoid_005ftrain shiftdatashiftdata  shanwavfshanwavf  sawtoothsawtooth  rectpulsrectpuls  pulstranpulstran  morletmorlet meyerauxmeyeraux mexihatmexihat gmonopulsgmonopuls gauspulsgauspuls diricdiric cmorwavfcmorwavf chirpchirp bufferbuffer  ö寝”{`?&ÿâɬ}dA, ö .% %zerocrossingzerocrossing- wrevwrev, wkeepwkeep +% %upsamplefillupsamplefill* schtrigschtrig,)1 1sampled2continuoussampled2continuous( primitiveprimitive' marcumqmarcumq& fracshiftfracshift$%) )clustersegmentclustersegment$ bufferbuffer-1## #statelevelsstatelevels" upsampleupsample! upfirdnupfirdn  resampleresample interpinterp! !downsampledownsample decimatedecimatesignal-1.4.5/doc/signal.qhc0000644000000000000000000034000014456505401013704 0ustar0000000000000000SQLite format 3@ ##.c ²¨†’$ º  w † ä h ó z ó H¾"¾fó| ¨b''tableVersionFilterVersionFilterCREATE TABLE VersionFilter (Version TEXT, FilterId INTEGER)n++tableComponentFilterComponentFilterCREATE TABLE ComponentFilter (ComponentName TEXT, FilterId INTEGER)u--tableComponentMappingComponentMappingCREATE TABLE ComponentMapping (ComponentId INTEGER, NamespaceId INTEGER)q))tableComponentTableComponentTableCREATE TABLE ComponentTable (ComponentId INTEGER PRIMARY KEY, Name TEXT)VtableFilterFilterCREATE TABLE Filter (FilterId INTEGER PRIMARY KEY, Name TEXT)b%%tableVersionTableVersionTableCREATE TABLE VersionTable (NamespaceId INTEGER, Version TEXT)))mtableTimeStampTableTimeStampTableCREATE TABLE TimeStampTable (NamespaceId INTEGER, FolderId INTEGER, FilePath TEXT, Size INTEGER, TimeStamp TEXT)551tableOptimizedFilterTableOptimizedFilterTableCREATE TABLE OptimizedFilterTable (NamespaceId INTEGER, FilterAttributeId INTEGER)(77otableFileAttributeSetTableFileAttributeSetTableCREATE TABLE FileAttributeSetTable (NamespaceId INTEGER, FilterAttributeSetId INTEGER, FilterAttributeId INTEGER) 33/tableContentsFilterTableContentsFilterTableCREATE TABLE ContentsFilterTable (FilterAttributeId INTEGER, ContentsId INTEGER )w --!tableIndexFilterTableIndexFilterTable CREATE TABLE IndexFilterTable (FilterAttributeId INTEGER, IndexId INTEGER)s ++tableFileFilterTableFileFilterTable CREATE TABLE FileFilterTable (FilterAttributeId INTEGER, FileId INTEGER)z ''3tableContentsTableContentsTable CREATE TABLE ContentsTable (Id INTEGER PRIMARY KEY, NamespaceId INTEGER, Data BLOB) !!‚ tableIndexTableIndexTable CREATE TABLE IndexTable (Id INTEGER PRIMARY KEY, Name TEXT, Identifier TEXT, NamespaceId INTEGER, FileId INTEGER, Anchor TEXT)''MtableFileNameTableFileNameTable CREATE TABLE FileNameTable (FolderId INTEGER, Name TEXT, FileId INTEGER PRIMARY KEY, Title TEXT)e'' tableSettingsTableSettingsTableCREATE TABLE SettingsTable (Key TEXT PRIMARY KEY, Value BLOB )9M'indexsqlite_autoindex_SettingsTable_1SettingsTableh##tableFilterTableFilterTableCREATE TABLE FilterTable (NameId INTEGER, FilterAttributeId INTEGER )l++tableFilterNameTableFilterNameTableCREATE TABLE FilterNameTable (Id INTEGER PRIMARY KEY, Name TEXT ){55tableFilterAttributeTableFilterAttributeTableCREATE TABLE FilterAttributeTable (Id INTEGER PRIMARY KEY, Name TEXT )u##1tableFolderTableFolderTableCREATE TABLE FolderTable (Id INTEGER PRIMARY KEY, NamespaceId INTEGER, Name TEXT )x))+tableNamespaceTableNamespaceTableCREATE TABLE NamespaceTable (Id INTEGER PRIMARY KEY, Name TEXT, FilePath TEXT ) ÙÙ%;!octave.community.signalsignal.qch ÷÷ doc    #Ô¶{fS>#9FullTextSearchFallback%CreationTimedº‹>) HideAddressBar- EnableAddressBarA EnableDocumentationManager; HideFilterFunctionality? EnableFilterFunctionality*-;LastRegisterTime2023-07-21T09:42:22.211 ?Z~“Î?k²́9FullTextSearchFallback%CreationTime)HideAddressBar-EnableAddressBarAEnableDocumentationManager;HideFilterFunctionality?EnableFilterFunctionality- LastRegisterTime ¦Á¦ !!signal.csssignal.css= #gsignal.htmlOctave Signal - Signal Toolkit for GNU octaveúú" ßßü øsignal.htmlhOctave Signal - Signal Toolkit for GNU octave Manual(signal.html#Overview1 OverviewDsignal.html#Installing-and-loading02 Installing and loading6signal.html#Windows-install&2.1 Windows install,signal.html#Installing2.2 Installing&signal.html#Loading2.3 Loading<signal.html#Function-Reference(3 Function Reference&signal.html#Signals3.1 Signals$signal.html#buffer3.1.1 buffer"signal.html#chirp3.1.2 chirp(signal.html#cmorwavf3.1.3 cmorwavf"signal.html#diric3.1.4 diric(signal.html#gauspuls3.1.5 gauspuls*signal.html#gmonopuls3.1.6 gmonopuls&signal.html#mexihat3.1.7 mexihat(signal.html#meyeraux3.1.8 meyeraux$signal.html#morlet3.1.9 morlet(signal.html#pulstran3.1.10 pulstran(signal.html#rectpuls3.1.11 rectpuls(signal.html#sawtooth3.1.12 sawtooth(signal.html#shanwavf3.1.13 shanwavf*signal.html#shiftdata 3.1.14 shiftdata:signal.html#sigmoid_005ftrain(3.1.15 sigmoid_train(signal.html#specgram3.1.16 specgram$signal.html#square3.1.17 square&signal.html#tripuls3.1.18 tripuls&signal.html#udecode3.1.19 udecode&signal.html#uencode3.1.20 uencode.signal.html#unshiftdata$3.1.21 unshiftdatasignal.html#vco3.1.22 vco<signal.html#Signal-Measurement,3.2 Signal Measurement*signal.html#findpeaks3.2.1 findpeaks*signal.html#peak2peak3.2.2 peak2peak(signal.html#peak2rms3.2.3 peak2rmssignal.html#rms3.2.4 rms signal.html#rssq3.2.5 rssqNsignal.html#Correlation-and-Convolution>3.3 Correlation and Convolution"signal.html#cconv3.3.1 cconv&signal.html#convmtx3.3.2 convmtx"signal.html#wconv3.3.3 wconv"signal.html#xcorr3.3.4 xcorr$signal.html#xcorr23.3.5 xcorr2 signal.html#xcov3.3.6 xcov*sign      ØØ& !3signal.qch02023-07-21T09:42:22 ûû  øødoc ûû   ¢^ëØ¿¬“xaH3èÏ´t_H1 û ́ Ñ ¶ } j S @ -   î Ù À ¥ ˆ q T = * ø ß Î ³ – y ` K 6   ï Ú Å ² Ÿ w d O < )  ù à Ë ¶ Ÿ w ^ G .  ñÚÁ®•|]Hï̃ͺŸ€mX9& ₫ï̃É´‘‚sdS<+öăĐ®•€o`K2 ỡΰjB&øÚÀ¦”~`D,üäÊ´ˆpV<"ø̃Àªx^" upsampleupsample! upfirdnupfirdn  resampleresample interpinterp! !downsampledownsample decimatedecimate data2fundata2fun  lpclpc levinsonlevinson invfreqzinvfreqz invfreqsinvfreqs invfreqinvfreq aryulearyule arburgarburg windowwindow welchwinwelchwin ultrwinultrwin tukeywintukeywin triangtriang rectwinrectwin parzenwinparzenwin ! !nuttallwinnuttallwin  kaiserkaiser  hannhann  gausswingausswin  gaussiangaussian! !flattopwinflattopwin chebwinchebwin boxcarboxcar bohmanwinbohmanwin%+ +blackmannuttallblackmannuttall#) )blackmanharrisblackmanharris# #barthannwinbarthannwin! !tfestimatetfestimate  tfetfe pyulearpyulear~ pwelchpwelch} pow2dbpow2db| pburgpburg{ mscoheremscoherez db2powdb2pow y csdcsdx cpsdcpsdw coherecoherev !ar_psdar_005fpsd u 1__powerg_t_005f_005fpowert rcepsrcepss ifwhtifwhtr ifhtifhtq idstidstp idct2idct2o idctidctn hilberthilbertm fwhtfwht l fhtfht k dwtdwt j dstdst!i' 'digitrevorderdigitrevorderh dftmtxdftmtxg dctmtxdctmtxf dct2dct2 e dctdct d cztcztc cplxrealcplxrealb ccepsccepsa# #bitrevorderbitrevorder` sgolaysgolay_ remezremez^ 'qp_kaiserqp_005fkaiser] kaiserordkaiserord\ firlsfirls[ fir2fir2Z fir1fir1Y cl2bpcl2bpX sftranssftrans-W+ ;pei_tseng_notchpei_005ftseng_005fnotchV ncauerncauerU# #invimpinvarinvimpinvarT impinvarimpinvarS firpmordfirpmordR firpmfirpmQ ellipordellipordP ellipapellipapO ellipellipN cheby2cheby2M cheby1cheby1L cheb2ordcheb2ordK cheb2apcheb2apJ cheb1ordcheb1ordI cheb1apcheb1apH chebchebG buttordbuttordF butterbutterE buttapbuttapD bilinearbilinearC besselfbesselfB besselapbesselapA zp2tfzp2tf@ zp2sszp2ss? zp2soszp2sos> tf2zptf2zp= tf2sstf2ss< tf2sostf2sos; ss2zpss2zp: ss2tfss2tf9 sos2zpsos2zp8 sos2tfsos2tf7 sos2sssos2ss6 residuezresiduez5 residuedresidued4 zplanezplane3 phasezphasez2 isstableisstable1! !isminphaseisminphase0! !ismaxphaseismaxphase/ isallpassisallpass. impzimpz- grpdelaygrpdelay, fwhmfwhm+! )freqs_plotfreqs_005fplot* freqsfreqs) filtordfiltord(! !filternormfilternorm' sosfiltsosfilt&! !sgolayfiltsgolayfilt% movingrmsmovingrms$ medfilt1medfilt1# filticfiltic" filtfiltfiltfilt! xcovxcov  xcorr2xcorr2 xcorrxcorr wconvwconv convmtxconvmtx cconvcconv rssqrssq  rmsrms peak2rmspeak2rms peak2peakpeak2peak findpeaksfindpeaks  vcovco# #unshiftdataunshiftdata uencodeuencode udecodeudecode tripulstripuls squaresquare specgramspecgram%' /sigmoid_trainsigmoid_005ftrain shiftdatashiftdata  shanwavfshanwavf  sawtoothsawtooth  rectpulsrectpuls  pulstranpulstran  morletmorlet meyerauxmeyeraux mexihatmexihat gmonopulsgmonopuls gauspulsgauspuls diricdiric cmorwavfcmorwavf chirpchirp bufferbuffer ¢àÈ¢†nR$ êÖÄ¢.% %zerocrossingzerocrossing- wrevwrev, wkeepwkeep+% %upsamplefillupsamplefill* schtrigschtrig+)1 1sampled2continuoussampled2continuous( primitiveprimitive' marcumqmarcumq& fracshiftfracshift#%) )clustersegmentclustersegment$ bufferbuffer-1## #statelevelsstatelevelsal.html#Filtering3.4 Filtering(signal.html#filtfilt3.4.1 filtfilt$signal.html#filtic3.4.2 filtic(signal.html#medfilt13.4.3 medfilt1*signal.html#movingrms3.4.4 movingrms,signal.html#sgolayfilt 3.4.5 sgolayfilt&signal.html#sosfilt3.4.6 sosfilt6signal.html#Filter-Analysis&3.5 Filter Analysis,signal.html#filternorm 3.5.1 filternorm&signal.html#filtord3.5.2 filtord"signal.html#freqs3.5.3 freqs4signal.html#freqs_005fplot 3.5.4 freqs_plot signal.html#fwhm3.5.5 fwhm(signal.html#grpdelay3.5.6 grpdelay signal.html#impz3.5.7 impz*signal.html#isallpass3.5.8 isallpass,signal.html#ismaxphase 3.5.9 ismaxphase,signal.html#isminphase"3.5.10 isminphase(signal.html#isstable3.5.11 isstable$signal.html#phasez3.5.12 phasez$signal.html#zplane3.5.13 zplane:signal.html#Filter-Conversion*3.6 Filter Conversion(signal.html#residued3.6.1 residued(signal.html#residuez3.6.2 residuez$signal.html#sos2ss3.6.3 sos2ss$signal.html#sos2tf3.6.4 sos2tf$signal.html#sos2zp3.6.5 sos2zp"signal.html#ss2tf3.6.6 ss2tf"signal.html#ss2zp3.6.7 ss2zp$signal.html#tf2sos3.6.8 tf2sos"signal.html#tf2ss3.6.9 tf2ss"signal.html#tf2zp3.6.10 tf2zp$signal.html#zp2sos3.6.11 zp2sos"signal.html#zp2ss3.6.12 zp2ss"signal.html#zp2tf3.6.13 zp2tf:signal.html#IIR-Filter-Design*3.7 IIR Filter Design(signal.html#besselap3.7.1 besselap&signal.html#besself3.7.2 besself(signal.html#bilinear3.7.3 bilinear$signal.html#buttap3.7.4 buttap$signal.html#butter3.7.5 butter&signal.html#buttord3.7.6 buttord signal.html#cheb3.7.7 cheb&signal.html#cheb1ap3.7.8 cheb1ap(signal.html#cheb1ord3.7.9 cheb1ord&signal.html#cheb2ap3.7.10 cheb2ap(signal.html#cheb2ord3.7.11 cheb2ord$signal.html#cheby13.7.12 cheby1$signal.html#cheby23.7.13 cheby2"signal.html#ellip3.7.14 ellip&signal.html#ellipap3.7.15 ellipap(signal.html#ellipord3.7.16 ellipord"signal.html#firpm3.7.17 firpm(signal.html#firpmord3.7.18 firpmord(signal.html#impinvar3.7.19 impinvar.signal.html#invimpinvar$3.7.20 invimpinvar$signal.html#ncauer3.7.21 ncauerFsignal.html#pei_005ftseng_005fnotch,3.7.22 pei_tseng_notch&signal.html#sftrans3.7.23 sftrans:signal.html#FIR-Filter-Design*3.8 FIR Filter Design"signal.html#cl2bp3.8.1 cl2bp signal.html#fir13.8.2 fir1 signal.html#fir23.8.3 fir2"signal.html#firls3.8.4 firls*signal.html#kaiserord3.8.5 kaiserord2signal.html#qp_005fkaiser3.8.6 qp_kaiser"signal.html#remez3.8.7 remez$signal.html#sgolay3.8.8 sgolay,signal.html#Transforms3.9 Transforms.signal.html#bitrevorder"3.9.1 bitrevorder"signal.html#cceps3.9.2 cceps(signal.html#cplxreal3.9.3 cplxrealsignal.html#czt3.9.4 cztsignal.html#dct3.9.5 dct signal.html#dct23.9.6 dct2$signal.html#dctmtx3.9.7 dctmtx$signal.html#dftmtx3.9.8 dftmtx2signal.html#digitrevorder&3.9.9 digitrevordersignal.html#dst3.9.10 dstsignal.html#dwt3.9.11 dwtsignal.html#fht3.9.12 fht signal.html#fwht3.9.13 fwht&signal.html#hilbert3.9.14 hilbert signal.html#idct3.9.15 idct"signal.html#idct23.9.16 idct2 signal.html#idst3.9.17 idst signal.html#ifht3.9.18 ifht"signal.html#ifwht3.9.19 ifwht"signal.html#rceps3.9.20 rcepsFsignal.html#Power-Spectrum-Analysis83.10 Power Spectrum Analysis<signal.html#g_t_005f_005fpower3.10.1 __power,signal.html#ar_005fpsd3.10.2 ar_psd$signal.html#cohere3.10.3 cohere signal.html#cpsd3.10.4 cpsdsignal.html#csd3.10.5 csd$signal.html#db2pow3.10.6 db2pow(signal.html#mscohere3.10.7 mscohere"signal.html#pburg3.10.8 pburg$signal.html#pow2db3.10.9 pow2db$signal.html#pwelch3.10.10 pwelch&signal.html#pyulear3.10.11 pyulearsignal.html#tfe3.10.12 tfe,signal.html#tfestimate$3.10.13 tfestimate8signal.html#Window-Functions*3.11 Window Functions.signal.html#barthannwin$3.11.1 barthannwin4signal.html#blackmanharris*3.11.2 blackmanharris6signal.html#blackmannuttall,3.11.3 blackmannuttall*signal.html#bohmanwin 3.11.4 bohmanwin$signal.html#boxcar3.11.5 boxcar&signal.html#chebwin3.11.6 chebwin,signal.html#flattopwin"3.11.7 flattopwin(signal.html#gaussian3.11.8 gaussian(signal.html#gausswin3.11.9 gausswin signal.html#hann3.11.10 hann$signal.html#kaiser3.11.11 kaiser,signal.html#nuttallwin$3.11.12 nuttallwin*signal.html#parzenwin"3.11.13 parzenwin&signal.html#rectwin3.11.14 rectwin$signal.html#triang3.11.15 triang(signal.html#tukeywin 3.11.16 tukeywin&signal.html#ultrwin3.11.17 ultrwin(signal.html#welchwin 3.11.18 welchwin$signal.html#window3.11.19 windowBsignal.html#System-Identification43.12 System Identification$signal.html#arburg3.12.1 arburg$signal.html#aryule3.12.2 aryule&signal.html#invfreq3.12.3 invfreq(signal.html#invfreqs3.12.4 invfreqs(signal.html#invfreqz3.12.5 invfreqz(signal.html#levinson3.12.6 levinsonsignal.html#lpc3.12.7 lpc<signal.html#Sample-Rate-Change.3.13 Sample Rate Change(signal.html#data2fun3.13.1 data2fun(signal.html#decimate3.13.2 decimate,signal.html#downsample"3.13.3 downsample$signal.html#interp3.13.4 interp(signal.html#resample3.13.5 resample&signal.html#upfirdn3.13.6 upfirdn(signal.html#upsample3.13.7 upsample2signal.html#Pulse-Metrics$3.14 Pulse Metrics.signal.html#statelevels$3.14.1 statelevels&signal.html#Utility3.15 Utility(signal.html#buffer-13.15.1 buffer4signal.html#clustersegment*3.15.2 clustersegment*signal.html#fracshift 3.15.3 fracshift&signal.html#marcumq3.15.4 marcumq*signal.html#primitive 3.15.5 primitive<signal.html#sampled2continuous23.15.6 sampled2continuous&signal.html#schtrig3.15.7 schtrig0signal.html#upsamplefill&3.15.8 upsamplefill"signal.html#wkeep3.15.9 wkeep signal.html#wrev3.15.10 wrev0signal.html#zerocrossing(3.15.11 zerocrossingsignal-1.4.5/doc/signal.texi0000644000000000000000000000743014456505401014111 0ustar0000000000000000% Copyright (C) 1996-2023 The Octave Project Developers % % This file is part of Octave. % % Octave is free software: you can redistribute it and/or modify it % under the terms of the GNU General Public License as published by % the Free Software Foundation, either version 3 of the License, or % (at your option) any later version. % % Octave is distributed in the hope that it will be useful, but % WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with Octave; see the file COPYING. If not, see % . \input texinfo @c Octave Signal - Signal Toolkit for GNU octave. @c For manually generating the documentation use @c LANGUAGE=en makeinfo --html --no-split signal.texi @c %*** Start of HEADER @documentencoding UTF-8 @setfilename signal.info @settitle Octave Signal - Signal Toolkit for GNU octave @afourpaper @paragraphindent 0 @finalout @c @afourwide @c %*** End of the HEADER @dircategory Math @direntry * Octave Signal: (signal). Signal Toolkit for Octave @end direntry @include version.texi @include macros.texi @c ------------------------------------------------------------------------- @c @contents @c ------------------------------------------------------------------------- @ifnottex @node Top @top Octave Signal Toolkit Copyright © The Octave Project Developers Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions. @end ifnottex @c ------------------------------------------------------------------------- @node Overview @chapter Overview @cindex Overview The Signal Toolkit contains signal processing tools, including filtering, windowing and display functions. @c ------------------------------------------------------------------------- @node Installing and loading @chapter Installing and loading @cindex Installing and loading The Signal Toolkit must be installed and then loaded to be used. It can be installed in @acronym{GNU} Octave directly from octave-forge, @section Windows install @cindex Windows install If running in Windows, the package may already be installed, to check run: @example pkg list signal @end example @section Installing @cindex Installing With an internet connection available, the Signal package can be installed from octave-forge using the following command within @acronym{GNU} Octave: @example pkg install -forge signal @end example The latest released version of the toolkit will be downloaded and installed. Otherwise, if the package file has already been downloaded it can be installed using the follwoing command in @acronym{GNU} Octave: @example pkg install signal-@value{VERSION}.tar.gz @end example @section Loading @cindex Loading Regardless of the method of installing the toolkit, in order to use its functions, the toolkit must be loaded using the pkg load command: @example pkg load signal @end example The toolkit must be loaded on each @acronym{GNU} Octave session. @c ------------------------------------------------------------------------- @node Function Reference @chapter Function Reference @cindex Function Reference @include functions.texi @c ------------------------------------------------------------------------- @bye signal-1.4.5/doc/version.texi0000644000000000000000000000013314456505401014312 0ustar0000000000000000@c autogenerated from Makefile @set VERSION 1.4.5 @set PACKAGE signal @set DATE 2023-07-21 signal-1.4.5/inst/0000755000000000000000000000000014456505401012145 5ustar0000000000000000signal-1.4.5/inst/PKG_ADD0000644000000000000000000000070714456505401013165 0ustar0000000000000000# on package load, attempt to load docs try pkg_dir = fileparts (fullfile (mfilename ("fullpath"))); doc_file = fullfile (pkg_dir, "doc", "signal.qch"); if exist(doc_file, "file") if exist("__event_manager_register_documentation__") __event_manager_register_documentation__ (doc_file); elseif exist("__event_manager_register_doc__") __event_manager_register_doc__ (doc_file); endif endif catch # do nothing end_try_catch signal-1.4.5/inst/PKG_DEL0000644000000000000000000000072114456505401013175 0ustar0000000000000000# on package load, attempt to unload docs try pkg_dir = fileparts (fullfile (mfilename ("fullpath"))); doc_file = fullfile (pkg_dir, "doc", "signal.qch"); if exist(doc_file, "file") if exist("__event_manager_unregister_documentation__") __event_manager_unregister_documentation__ (doc_file); elseif exist("__event_manager_unregister_doc__") __event_manager_unregister_doc__ (doc_file); endif endif catch # do nothing end_try_catch signal-1.4.5/inst/__firpm_probe__.m0000644000000000000000000000246114456505401015426 0ustar0000000000000000######################################################################## ## ## Copyright (C) 2021 The Octave Project Developers ## ## See the file COPYRIGHT.md in the top-level directory of this ## distribution or . ## ## This file is part of Octave. ## ## Octave is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## Octave is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## ######################################################################## function is_odd = __firpm_probe__ (respFn, params) try symm=feval (respFn, 'defaults', params); catch is_odd=0; return end_try_catch if (strcmp (symm, 'even')) is_odd=0; elseif (strcmp (symm, 'odd' )) is_odd=1; else error ("firpm respFn symmetry must be 'even' or 'odd'") endif endfunction signal-1.4.5/inst/__power.m0000644000000000000000000000610514456505401013757 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{P}, @var{w}] =} __power (@var{b}, @var{a}) ## @deftypefnx {Function File} {[@dots{}] =} __power (@var{b}, @var{a}, @var{nfft}) ## @deftypefnx {Function File} {[@dots{}] =} __power (@var{b}, @var{a}, @var{nfft}, @var{Fs}) ## @deftypefnx {Function File} {[@dots{}] =} __power (@var{b}, @var{a}, @var{nfft}, @var{Fs}, @var{range}) ## @deftypefnx {Function File} {[@dots{}] =} __power (@var{b}, @var{a}, @var{nfft}, @var{Fs}, @var{range}, @var{units}) ## @deftypefnx {Function File} {} __power (@dots{}) ## ## Plot the power spectrum of the given ARMA model. ## ## b, a: filter coefficients (b=numerator, a=denominator) ## nfft is number of points at which to sample the power spectrum ## Fs is the sampling frequency of x ## range is 'half' (default) or 'whole' ## units is 'squared' or 'db' (default) ## range and units may be specified any time after the filter, in either ## order ## ## Returns P, the magnitude vector, and w, the frequencies at which it ## is sampled. If there are no return values requested, then plot the power ## spectrum and don't return anything. ## @end deftypefn ## FIXME: consider folding this into freqz --- just one more parameter to ## distinguish between 'linear', 'log', 'logsquared' and 'squared' function varargout = __power (b, a, varargin) if (nargin < 2 || nargin > 6) print_usage; endif nfft = []; Fs = []; range = []; range_fact = 1.0; units = []; pos = 0; for i=1:length(varargin) arg = varargin{i}; if strcmp(arg, 'squared') || strcmp(arg, 'db') units = arg; elseif strcmp(arg, 'whole') range = arg; range_fact = 1.0; elseif strcmp(arg, 'half') range = arg; range_fact = 2.0; elseif ischar(arg) usage(usagestr); elseif pos == 0 nfft = arg; pos++; elseif pos == 1 Fs = arg; pos++; else usage(usagestr); endif endfor if isempty(nfft); nfft = 256; endif if isempty(Fs); Fs = 2; endif if isempty(range) range = 'half'; range_fact = 2.0; endif [P, w] = freqz(b, a, nfft, range, Fs); P = (range_fact/Fs)*(P.*conj(P)); if nargout == 0, if strcmp(units, 'squared') plot(w, P, ";;"); else plot(w, 10.0*log10(abs(P)), ";;"); endif endif if nargout >= 1, varargout{1} = P; endif if nargout >= 2, varargout{2} = w; endif endfunction signal-1.4.5/inst/ar_psd.m0000644000000000000000000002717114456505401013603 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} ar_psd (@var{a}, @var{v}) ## @deftypefnx {Function File} {} ar_psd (@var{a}, @var{v}, @var{freq}) ## @deftypefnx {Function File} {} ar_psd (@var{a}, @var{v}, @var{freq}, @var{Fs}) ## @deftypefnx {Function File} {} ar_psd (@dots{}, @var{range}) ## @deftypefnx {Function File} {} ar_psd (@dots{}, @var{method}) ## @deftypefnx {Function File} {} ar_psd (@dots{}, @var{plottype}) ## @deftypefnx {Function File} {[@var{psd}, @var{f_out}] =} ar_psd (@dots{}) ## ## Calculate the power spectrum of the autoregressive model ## ## @example ## @group ## M ## x(n) = sqrt(v).e(n) + SUM a(k).x(n-k) ## k=1 ## @end group ## @end example ## ## where @math{x(n)} is the output of the model and @math{e(n)} is white noise. ## This function is intended for use with ## @code{[a, v, k] = arburg (x, poles, criterion)} ## which use the Burg (1968) method to calculate a "maximum entropy" ## autoregressive model of @var{x}. ## ## If the @var{freq} argument is a vector (of frequencies) the spectrum is ## calculated using the polynomial method and the @var{method} argument is ## ignored. For scalar @var{freq}, an integer power of 2, or @var{method} = ## "FFT", causes the spectrum to be calculated by FFT. Otherwise, the spectrum ## is calculated as a polynomial. It may be computationally more ## efficient to use the FFT method if length of the model is not much ## smaller than the number of frequency values. The spectrum is scaled so ## that spectral energy (area under spectrum) is the same as the time-domain ## energy (mean square of the signal). ## ## ARGUMENTS: ## All but the first two arguments are optional and may be empty. ## @itemize ## @item ## @var{a} ## list of M=(order+1) autoregressive model ## coefficients. The first element of "ar_coeffs" is the ## zero-lag coefficient, which always has a value of 1. ## @item ## @var{v} ## square of the moving-average coefficient of the AR model. ## @item ## @var{freq} ## frequencies at which power spectral density is calculated, or a scalar ## indicating the number of uniformly distributed frequency ## values at which spectral density is calculated. ## (default = 256) ## @item ## @var{Fs} ## sampling frequency (Hertz) (default=1) ## @end itemize ## ## CONTROL-STRING ARGUMENTS -- each of these arguments is a character string. ## Control-string arguments can be in any order after the other arguments. ## ## Range: ## ## 'half', 'onesided' : frequency range of the spectrum is ## from zero up to but not including sample_f/2. Power ## from negative frequencies is added to the positive ## side of the spectrum. ## 'whole', 'twosided' : frequency range of the spectrum is ## -sample_f/2 to sample_f/2, with negative frequencies ## stored in "wrap around" order after the positive ## frequencies; e.g. frequencies for a 10-point 'twosided' ## spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 ## 'shift', 'centerdc' : same as 'whole' but with the first half ## of the spectrum swapped with second half to put the ## zero-frequency value in the middle. (See "help ## fftshift". If "freq" is vector, 'shift' is ignored. ## If model coefficients "ar_coeffs" are real, the default ## range is 'half', otherwise default range is 'whole'. ## ## Method: ## ## 'fft': use FFT to calculate power spectrum. ## 'poly': calculate power spectrum as a polynomial of 1/z ## N.B. this argument is ignored if the "freq" argument is a ## vector. The default is 'poly' unless the "freq" ## argument is an integer power of 2. ## ## Plot type: ## ## 'plot', 'semilogx', 'semilogy', 'loglog', 'squared' or 'db': ## specifies the type of plot. The default is 'plot', which ## means linear-linear axes. 'squared' is the same as 'plot'. ## 'dB' plots "10*log10(psd)". This argument is ignored and a ## spectrum is not plotted if the caller requires a returned ## value. ## ## RETURNED VALUES: ## If returned values are not required by the caller, the spectrum ## is plotted and nothing is returned. ## @itemize ## @item ## @var{psd} ## estimate of power-spectral density ## @item ## @var{f_out} ## frequency values ## @end itemize ## ## REFERENCE ## [1] Equation 2.28 from Steven M. Kay and Stanley Lawrence Marple Jr.: ## "Spectrum analysis -- a modern perspective", ## Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981 ## ## @end deftypefn function varargout = ar_psd(a,v,varargin) ## ## Check fixed arguments if ( nargin < 2 ) error( 'ar_psd: needs at least 2 args. Use help ar_psd.' ); elseif ( ~isvector(a) || length(a)<2 ) error( 'ar_psd: arg 1 (a) must be vector, length>=2.' ); elseif ( ~isscalar(v) ) error( 'ar_psd: arg 2 (v) must be real scalar >0.' ); else real_model = isreal(a); ## ## default values for optional arguments freq = 256; user_freqs = 0; ## boolean: true for user-specified frequencies Fs = 1.0; ## FFT padding factor (is also frequency range divisor): 1=whole, 2=half. pad_fact = 1 + real_model; do_shift = 0; force_FFT = 0; force_poly = 0; plot_type = 1; ## ## decode and check optional arguments ## end_numeric_args is boolean; becomes true at 1st string arg end_numeric_args = 0; for iarg = 1:length(varargin) arg = varargin{iarg}; end_numeric_args = end_numeric_args || ischar(arg); ## skip empty arguments if ( isempty(arg) ) 1; ## numeric optional arguments must be first, cannot follow string args ## N.B. older versions of matlab may not have the function "error" so ## the user writes "function error(msg); disp(msg); end" and we need ## a "return" here. elseif ( ~ischar(arg) ) if ( end_numeric_args ) error( 'ar_psd: control arg must be string.' ); ## ## first optional numeric arg is "freq" elseif ( iarg == 1 ) user_freqs = isvector(arg) && length(arg)>1; if ( ~isscalar(arg) && ~user_freqs ) error( 'ar_psd: arg 3 (freq) must be vector or scalar.' ); elseif ( ~user_freqs && ( ~isreal(arg) || ... fix(arg)~=arg || arg <= 2 || arg >= 1048576 ) ) error('ar_psd: arg 3 (freq) must be integer >=2, <=1048576' ); elseif ( user_freqs && ~isreal(arg) ) error( 'ar_psd: arg 3 (freq) vector must be real.' ); endif freq = arg(:); # -> column vector ## ## second optional numeric arg is "Fs" - sampling frequency elseif ( iarg == 2 ) if ( ~isscalar(arg) || ~isreal(arg) || arg<=0 ) error( 'ar_psd: arg 4 (Fs) must be real positive scalar.' ); endif Fs = arg; ## else error( 'ar_psd: control arg must be string.' ); endif ## ## decode control-string arguments elseif ( strcmp(arg,'plot') || strcmp(arg,'squared') ) plot_type = 1; elseif ( strcmp(arg,'semilogx') ) plot_type = 2; elseif ( strcmp(arg,'semilogy') ) plot_type = 3; elseif ( strcmp(arg,'loglog') ) plot_type = 4; elseif ( strcmp(arg,'dB') ) plot_type = 5; elseif ( strcmp(arg,'fft') ) force_FFT = 1; force_poly = 0; elseif ( strcmp(arg,'poly') ) force_FFT = 0; force_poly = 1; elseif ( strcmp(arg,'half') || strcmp(arg,'onesided') ) pad_fact = 2; # FFT zero-padding factor (pad FFT to double length) do_shift = 0; elseif ( strcmp(arg,'whole') || strcmp(arg,'twosided') ) pad_fact = 1; # FFT zero-padding factor (do not pad) do_shift = 0; elseif ( strcmp(arg,'shift') || strcmp(arg,'centerdc') ) pad_fact = 1; do_shift = 1; else error( 'ar_psd: string arg: illegal value: %s', arg ); endif endfor ## end of decoding and checking args ## if ( user_freqs ) ## user provides (column) vector of frequencies if ( any(abs(freq)>Fs/2) ) error( 'ar_psd: arg 3 (freq) cannot exceed half sampling frequency.' ); elseif ( pad_fact==2 && any(freq<0) ) error( 'ar_psd: arg 3 (freq) must be positive in onesided spectrum' ); endif freq_len = length(freq); fft_len = freq_len; use_FFT = 0; do_shift = 0; else ## internally generated frequencies freq_len = freq; freq = (Fs/pad_fact/freq_len) * [0:freq_len-1]'; ## decide which method to use (poly or FFT) is_power_of_2 = rem(log(freq_len),log(2))<10.*eps; use_FFT = ( ~ force_poly && is_power_of_2 ) || force_FFT; fft_len = freq_len * pad_fact; endif ## ## calculate denominator of Equation 2.28, Kay and Marple, ref [1]Jr.: len_coeffs = length(a); if ( use_FFT ) ## FFT method fft_out = fft( [ a(:); zeros(fft_len-len_coeffs,1) ] ); else ## polynomial method ## complex data on "half" frequency range needs -ve frequency values if ( pad_fact==2 && ~real_model ) freq = [freq; -freq(freq_len:-1:1)]; fft_len = 2*freq_len; endif fft_out = polyval( a(len_coeffs:-1:1), exp( (-i*2*pi/Fs) * freq ) ); endif ## ## The power spectrum (PSD) is the scaled squared reciprocal of amplitude ## of the FFT/polynomial. This is NOT the reciprocal of the periodogram. ## The PSD is a continuous function of frequency. For uniformly ## distributed frequency values, the FFT algorithm might be the most ## efficient way of calculating it. ## psd = ( v / Fs ) ./ ( fft_out .* conj(fft_out) ); ## ## range='half' or 'onesided', ## add PSD at -ve frequencies to PSD at +ve frequencies ## N.B. unlike periodogram, PSD at zero frequency _is_ doubled. if ( pad_fact==2 ) freq = freq(1:freq_len); if ( real_model ) ## real data, double the psd psd = 2 * psd(1:freq_len); elseif ( use_FFT ) ## complex data, FFT method, internally-generated frequencies psd = psd(1:freq_len)+[psd(1); psd(fft_len:-1:freq_len+2)]; else ## complex data, polynomial method ## user-defined and internally-generated frequencies psd = psd(1:freq_len)+psd(fft_len:-1:freq_len+1); endif ## ## range='shift' ## disabled for user-supplied frequencies ## Shift zero-frequency to the middle (pad_fact==1) elseif ( do_shift ) len2 = fix((fft_len+1)/2); psd = [psd(len2+1:fft_len); psd(1:len2)]; freq = [freq(len2+1:fft_len)-Fs; freq(1:len2)]; endif ## ## Plot the spectrum if there are no return variables. if ( nargout >= 2 ) varargout{1} = psd; varargout{2} = freq; elseif ( nargout == 1 ) varargout{1} = psd; else if ( plot_type == 1 ) plot(freq,psd); elseif ( plot_type == 2 ) semilogx(freq,psd); elseif ( plot_type == 3 ) semilogy(freq,psd); elseif ( plot_type == 4 ) loglog(freq,psd); elseif ( plot_type == 5 ) plot(freq,10*log10(psd)); endif endif endif endfunction signal-1.4.5/inst/arburg.m0000644000000000000000000002272514456505401013615 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{a}, @var{v}, @var{k}] =} arburg (@var{x}, @var{poles}) ## @deftypefnx {Function File} {[@var{a}, @var{v}, @var{k}] =} arburg (@var{x}, @var{poles}, @var{criterion}) ## ## Calculate coefficients of an autoregressive (AR) model of complex data ## @var{x} using the whitening lattice-filter method of Burg (1968). The ## inverse of the model is a moving-average filter which reduces @var{x} to ## white noise. The power spectrum of the AR model is an estimate of the ## maximum entropy power spectrum of the data. The function @code{ar_psd} ## calculates the power spectrum of the AR model. ## ## ARGUMENTS: ## @itemize ## @item ## @var{x} ## sampled data ## @item ## @var{poles} ## number of poles in the AR model or limit to the number of poles if a ## valid @var{criterion} is provided. ## @item ## @var{criterion} ## model-selection criterion. Limits the number of poles so that spurious ## poles are not added when the whitened data has no more information ## in it (see Kay & Marple, 1981). Recognized values are ## 'AKICc' -- approximate corrected Kullback information criterion (recommended), ## 'KIC' -- Kullback information criterion ## 'AICc' -- corrected Akaike information criterion ## 'AIC' -- Akaike information criterion ## 'FPE' -- final prediction error" criterion ## The default is to NOT use a model-selection criterion ## @end itemize ## ## RETURNED VALUES: ## @itemize ## @item ## @var{a} ## list of (P+1) autoregression coefficients; for data input @math{x(n)} and ## white noise @math{e(n)}, the model is ## ## @example ## @group ## P+1 ## x(n) = sqrt(v).e(n) + SUM a(k).x(n-k) ## k=1 ## @end group ## @end example ## ## @var{v} ## mean square of residual noise from the whitening operation of the Burg ## lattice filter. ## @item ## @var{k} ## reflection coefficients defining the lattice-filter embodiment of the model ## @end itemize ## ## HINTS: ## ## (1) arburg does not remove the mean from the data. You should remove ## the mean from the data if you want a power spectrum. A non-zero mean ## can produce large errors in a power-spectrum estimate. See ## "help detrend". ## (2) If you don't know what the value of "poles" should be, choose the ## largest (reasonable) value you could want and use the recommended ## value, criterion='AKICc', so that arburg can find it. ## E.g. arburg(x,64,'AKICc') ## The AKICc has the least bias and best resolution of the available ## model-selection criteria. ## (3) Autoregressive and moving-average filters are stored as polynomials ## which, in matlab, are row vectors. ## ## NOTE ON SELECTION CRITERION: ## ## AIC, AICc, KIC and AKICc are based on information theory. They attempt ## to balance the complexity (or length) of the model against how well the ## model fits the data. AIC and KIC are biased estimates of the asymmetric ## and the symmetric Kullback-Leibler divergence respectively. AICc and ## AKICc attempt to correct the bias. See reference [4]. ## ## ## REFERENCES: ## ## [1] John Parker Burg (1968) ## "A new analysis technique for time series data", ## NATO advanced study Institute on Signal Processing with Emphasis on ## Underwater Acoustics, Enschede, Netherlands, Aug. 12-23, 1968. ## ## [2] Steven M. Kay and Stanley Lawrence Marple Jr.: ## "Spectrum analysis -- a modern perspective", ## Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981 ## ## [3] William H. Press and Saul A. Teukolsky and William T. Vetterling and ## Brian P. Flannery ## "Numerical recipes in C, The art of scientific computing", 2nd edition, ## Cambridge University Press, 2002 --- Section 13.7. ## ## [4] Abd-Krim Seghouane and Maiza Bekara ## "A small sample model selection criterion based on Kullback's symmetric ## divergence", IEEE Transactions on Signal Processing, ## Vol. 52(12), pp 3314-3323, Dec. 2004 ## ## @seealso{ar_psd} ## @end deftypefn function varargout = arburg( x, poles, criterion ) ## ## Check arguments if ( nargin < 2 ) error( 'arburg(x,poles): Need at least 2 args.' ); elseif ( ~isvector(x) || length(x) < 3 ) error( 'arburg: arg 1 (x) must be vector of length >2.' ); elseif ( ~isscalar(poles) || ~isreal(poles) || fix(poles)~=poles || poles<=0.5) error( 'arburg: arg 2 (poles) must be positive integer.' ); elseif ( poles >= length(x)-2 ) ## lattice-filter algorithm requires "poles0 error( 'arburg: arg 2 (poles) must be less than length(x)-2.' ); elseif ( nargin>2 && ~isempty(criterion) && ... (~ischar(criterion) || size(criterion,1)~=1 ) ) error( 'arburg: arg 3 (criterion) must be string.' ); else ## ## Set the model-selection-criterion flags. ## is_AKICc, isa_KIC and is_corrected are short-circuit flags if ( nargin > 2 && ~isempty(criterion) ) is_AKICc = strcmp(criterion,'AKICc'); # AKICc isa_KIC = is_AKICc || strcmp(criterion,'KIC'); # KIC or AKICc is_corrected = is_AKICc || strcmp(criterion,'AICc'); # AKICc or AICc use_inf_crit = is_corrected || isa_KIC || strcmp(criterion,'AIC'); use_FPE = strcmp(criterion,'FPE'); if ( ~use_inf_crit && ~use_FPE ) error( 'arburg: value of arg 3 (criterion) not recognized' ); endif else use_inf_crit = 0; use_FPE = 0; endif ## ## f(n) = forward prediction error ## b(n) = backward prediction error ## Storage of f(n) and b(n) is a little tricky. Because f(n) is always ## combined with b(n-1), f(1) and b(N) are never used, and therefore are ## not stored. Not storing unused data makes the calculation of the ## reflection coefficient look much cleaner :) ## N.B. {initial v} = {error for zero-order model} = ## {zero-lag autocorrelation} = E(x*conj(x)) = x*x'/N ## E = expectation operator N = length(x); k = []; if ( size(x,1) > 1 ) # if x is column vector f = x(2:N); b = x(1:N-1); v = real(x'*x) / N; else # if x is row vector f = x(2:N).'; b = x(1:N-1).'; v = real(x*x') / N; endif ## new_crit/old_crit is the mode-selection criterion new_crit = abs(v); old_crit = 2 * new_crit; for p = 1:poles ## ## new reflection coeff = -2* E(f.conj(b)) / ( E(f^2)+E(b(^2) ) last_k= -2 * (b' * f) / ( f' * f + b' * b); ## Levinson-Durbin recursion for residual new_v = v * ( 1.0 - real(last_k * conj(last_k)) ); if ( p > 1 ) ## ## Apply the model-selection criterion and break out of loop if it ## increases (rather than decreases). ## Do it before we update the old model "a" and "v". ## ## * Information Criterion (AKICc, KIC, AICc, AIC) if ( use_inf_crit ) old_crit = new_crit; ## AKICc = log(new_v)+p/N/(N-p)+(3-(p+2)/N)*(p+1)/(N-p-2); ## KIC = log(new_v)+ 3 *(p+1)/N; ## AICc = log(new_v)+ 2 *(p+1)/(N-p-2); ## AIC = log(new_v)+ 2 *(p+1)/N; ## -- Calculate KIC, AICc & AIC by using is_AKICc, is_KIC and ## is_corrected to "short circuit" the AKICc calculation. ## The extra 4--12 scalar arithmetic ops should be quicker than ## doing if...elseif...elseif...elseif...elseif. new_crit = log(new_v) + is_AKICc*p/N/(N-p) + ... (2+isa_KIC-is_AKICc*(p+2)/N) * (p+1) / (N-is_corrected*(p+2)); if ( new_crit > old_crit ) break; endif ## ## (FPE) Final prediction error elseif ( use_FPE ) old_crit = new_crit; new_crit = new_v * (N+p+1)/(N-p-1); if ( new_crit > old_crit ) break; endif endif ## Update model "a" and "v". ## Use Levinson-Durbin recursion formula (for complex data). a = [ prev_a + last_k .* conj(prev_a(p-1:-1:1)) last_k ]; else # if( p==1 ) a = last_k; endif k = [ k; last_k ]; v = new_v; if ( p < poles ) prev_a = a; ## calculate new prediction errors (by recursion): ## f(p,n) = f(p-1,n) + k * b(p-1,n-1) n=2,3,...n ## b(p,n) = b(p-1,n-1) + conj(k) * f(p-1,n) n=2,3,...n ## remember f(p,1) is not stored, so don't calculate it; make f(p,2) ## the first element in f. b(p,n) isn't calculated either. nn = N-p; new_f = f(2:nn) + last_k * b(2:nn); b = b(1:nn-1) + conj(last_k) * f(1:nn-1); f = new_f; endif endfor varargout{1} = [1 a]; varargout{2} = v; if ( nargout>=3 ) varargout{3} = k; endif endif endfunction signal-1.4.5/inst/aryule.m0000644000000000000000000000470314456505401013630 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## Copyright (C) 2006 Peter Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{a} =} aryule (@var{x}, @var{p}) ## @deftypefnx {Function File} {[@var{a}, @var{v}, @var{k}] =} aryule (@var{x}, @var{p}) ## Fit an AR (@var{p})-model with Yule-Walker estimates. ## @table @var ## @item x ## data vector to estimate ## @item a ## AR coefficients ## @item v ## variance of white noise ## @item k ## reflection coefficients for use in lattice filter ## @end table ## ## The power spectrum of the resulting filter can be plotted with ## pyulear(x, p), or you can plot it directly with ar_psd(a,v,...). ## ## See also: ## pyulear, power, freqz, impz -- for observing characteristics of the model ## arburg -- for alternative spectral estimators ## ## Example: Use example from arburg, but substitute aryule for arburg. ## ## Note: Orphanidis '85 claims lattice filters are more tolerant of ## truncation errors, which is why you might want to use them. However, ## lacking a lattice filter processor, I haven't tested that the lattice ## filter coefficients are reasonable. ## @end deftypefn function [a, v, k] = aryule (x, p) if ( nargin~=2 ) print_usage; elseif ( ~isvector(x) || length(x)<3 ) error( 'aryule: arg 1 (x) must be vector of length >2' ); elseif ( ~isscalar(p) || fix(p)~=p || p > length(x)-2 ) error( 'aryule: arg 2 (p) must be an integer >0 and ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} barthannwin (@var{m}) ## Return the filter coefficients of a modified Bartlett-Hann window of length ## @var{m}. ## @seealso{rectwin, bartlett} ## @end deftypefn function w = barthannwin (m) if (nargin != 1) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("barthannwin: M must be a positive integer"); endif if (m == 1) w = 1; else N = m - 1; n = 0:N; w = 0.62 -0.48.*abs(n./(m-1) - 0.5)+0.38*cos(2.*pi*(n./(m-1)-0.5)); w = w'; endif endfunction %!assert (barthannwin (1), 1) %!assert (barthannwin (2), zeros (2, 1)) %% Test input validation %!error barthannwin () %!error barthannwin (0.5) %!error barthannwin (-1) %!error barthannwin (ones (1, 4)) %!error barthannwin (1, 2) signal-1.4.5/inst/besselap.m0000644000000000000000000000313714456505401014125 0ustar0000000000000000## Copyright (C) 2009 Thomas Sailer ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{zero}, @var{pole}, @var{gain}] =} besselap (@var{n}) ## Return bessel analog filter prototype. ## ## References: ## ## http://en.wikipedia.org/wiki/Bessel_polynomials ## @end deftypefn function [zero, pole, gain] = besselap (n) if (nargin>1 || nargin<1) print_usage; endif ## interpret the input parameters if (!(length(n)==1 && n == round(n) && n > 0)) error ("besselap: filter order n must be a positive integer"); endif p0=1; p1=[1 1]; for nn=2:n; px=(2*nn-1)*p1; py=[p0 0 0]; px=prepad(px,max(length(px),length(py)),0); py=prepad(py,length(px)); p0=p1; p1=px+py; endfor; ## p1 now contains the reverse bessel polynomial for n ## scale it by replacing s->s/w0 so that the gain becomes 1 p1=p1.*p1(length(p1)).^((length(p1)-1:-1:0)/(length(p1)-1)); zero=[]; pole=roots(p1); gain=1; endfunction signal-1.4.5/inst/besself.m0000644000000000000000000001034214456505401013746 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## Copyright (C) 2003 Doug Stewart ## Copyright (C) 2009 Thomas Sailer ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{b}, @var{a}] =} besself (@var{n}, @var{w}) ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} besself (@var{n}, @var{w}, "high") ## @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} besself (@dots{}) ## @deftypefnx {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} besself (@dots{}) ## @deftypefnx {Function File} {[@dots{}] =} besself (@dots{}, "z") ## Generate a Bessel filter. ## Default is a Laplace space (s) filter. ## ## [b,a] = besself(n, Wc) ## low pass filter with cutoff pi*Wc radians ## ## [b,a] = besself(n, Wc, 'high') ## high pass filter with cutoff pi*Wc radians ## ## [z,p,g] = besself(...) ## return filter as zero-pole-gain rather than coefficients of the ## numerator and denominator polynomials. ## ## [...] = besself(...,'z') ## return a discrete space (Z) filter, W must be less than 1. ## ## [a,b,c,d] = besself(...) ## return state-space matrices ## ## References: ## ## Proakis & Manolakis (1992). Digital Signal Processing. New York: ## Macmillan Publishing Company. ## @end deftypefn function [a, b, c, d] = besself (n, w, varargin) if (nargin > 4 || nargin < 2 || nargout > 4 || nargout < 2) print_usage (); endif ## interpret the input parameters if (! (isscalar (n) && (n == fix (n)) && (n > 0))) error ("besself: filter order N must be a positive integer"); endif stop = false; digital = false; for i = 1:numel (varargin) switch (varargin{i}) case "s" digital = false; case "z" digital = true; case {"high", "stop"} stop = true; case {"low", "pass"} stop = false; otherwise error ("besself: expected [high|stop] or [s|z]"); endswitch endfor ## FIXME: Band-pass and stop-band currently non-functional, remove ## this check once low-pass to band-pass transform is implemented. if (! isscalar (w)) error ("besself: band-pass and stop-band filters not yet implemented"); endif if (! ((numel (w) <= 2) && (rows (w) == 1 || columns (w) == 1))) error ("besself: frequency must be given as WC or [WL, WH]"); elseif ((numel (w) == 2) && (w(2) <= w(1))) error ("besself: W(1) must be less than W(2)"); endif if (digital && ! all ((w >= 0) & (w <= 1))) error ("besself: all elements of W must be in the range [0,1]"); elseif (! digital && ! all (w >= 0)) error ("besself: all elements of W must be in the range [0,inf]"); endif ## Prewarp to the band edges to s plane if (digital) T = 2; # sampling frequency of 2 Hz w = 2 / T * tan (pi * w / T); endif ## Generate splane poles for the prototype Bessel filter [zero, pole, gain] = besselap (n); ## splane frequency transform [zero, pole, gain] = sftrans (zero, pole, gain, w, stop); ## Use bilinear transform to convert poles to the z plane if (digital) [zero, pole, gain] = bilinear (zero, pole, gain, T); endif ## convert to the correct output form if (nargout == 2) a = real (gain * poly (zero)); b = real (poly (pole)); elseif (nargout == 3) a = zero; b = pole; c = gain; else ## output ss results [a, b, c, d] = zp2ss (zero, pole, gain); endif endfunction %% Test input validation %!error [a, b] = besself () %!error [a, b] = besself (1) %!error [a, b] = besself (1, 2, 3, 4, 5) %!error [a, b] = besself (.5, .2) %!error [a, b] = besself (3, .2, "invalid") signal-1.4.5/inst/bilinear.m0000644000000000000000000001113414456505401014110 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{Zb}, @var{Za}] =} bilinear (@var{Sb}, @var{Sa}, @var{T}) ## @deftypefnx {Function File} {[@var{Zb}, @var{Za}] =} bilinear (@var{Sz}, @var{Sp}, @var{Sg}, @var{T}) ## @deftypefnx {Function File} {[@var{Zz}, @var{Zp}, @var{Zg}] =} bilinear (@dots{}) ## Transform a s-plane filter specification into a z-plane ## specification. Filters can be specified in either zero-pole-gain or ## transfer function form. The input form does not have to match the ## output form. 1/T is the sampling frequency represented in the z plane. ## ## Note: this differs from the bilinear function in the signal processing ## toolbox, which uses 1/T rather than T. ## ## Theory: Given a piecewise flat filter design, you can transform it ## from the s-plane to the z-plane while maintaining the band edges by ## means of the bilinear transform. This maps the left hand side of the ## s-plane into the interior of the unit circle. The mapping is highly ## non-linear, so you must design your filter with band edges in the ## s-plane positioned at 2/T tan(w*T/2) so that they will be positioned ## at w after the bilinear transform is complete. ## ## The following table summarizes the transformation: ## ## @example ## +---------------+-----------------------+----------------------+ ## | Transform | Zero at x | Pole at x | ## | H(S) | H(S) = S-x | H(S)=1/(S-x) | ## +---------------+-----------------------+----------------------+ ## | 2 z-1 | zero: (2+xT)/(2-xT) | zero: -1 | ## | S -> - --- | pole: -1 | pole: (2+xT)/(2-xT) | ## | T z+1 | gain: (2-xT)/T | gain: (2-xT)/T | ## +---------------+-----------------------+----------------------+ ## @end example ## ## With tedious algebra, you can derive the above formulae yourself by ## substituting the transform for S into H(S)=S-x for a zero at x or ## H(S)=1/(S-x) for a pole at x, and converting the result into the ## form: ## ## @example ## H(Z)=g prod(Z-Xi)/prod(Z-Xj) ## @end example ## ## Please note that a pole and a zero at the same place exactly cancel. ## This is significant since the bilinear transform creates numerous ## extra poles and zeros, most of which cancel. Those which do not ## cancel have a "fill-in" effect, extending the shorter of the sets to ## have the same number of as the longer of the sets of poles and zeros ## (or at least split the difference in the case of the band pass ## filter). There may be other opportunistic cancellations but I will ## not check for them. ## ## Also note that any pole on the unit circle or beyond will result in ## an unstable filter. Because of cancellation, this will only happen ## if the number of poles is smaller than the number of zeros. The ## analytic design methods all yield more poles than zeros, so this will ## not be a problem. ## ## References: ## ## Proakis & Manolakis (1992). Digital Signal Processing. New York: ## Macmillan Publishing Company. ## @end deftypefn function [Zz, Zp, Zg] = bilinear(Sz, Sp, Sg, T) if nargin==3 T = Sg; [Sz, Sp, Sg] = tf2zp(Sz, Sp); elseif nargin!=4 print_usage; endif p = length(Sp); z = length(Sz); if z > p || p==0 error("bilinear: must have at least as many poles as zeros in s-plane"); endif ## ---------------- ------------------------- ------------------------ ## Bilinear zero: (2+xT)/(2-xT) pole: (2+xT)/(2-xT) ## 2 z-1 pole: -1 zero: -1 ## S -> - --- gain: (2-xT)/T gain: (2-xT)/T ## T z+1 ## ---------------- ------------------------- ------------------------ Zg = real(Sg * prod((2-Sz*T)/T) / prod((2-Sp*T)/T)); Zp = (2+Sp*T)./(2-Sp*T); if isempty(Sz) Zz = -ones(size(Zp)); else Zz = [(2+Sz*T)./(2-Sz*T)]; Zz = postpad(Zz, p, -1); endif if nargout==2, [Zz, Zp] = zp2tf(Zz, Zp, Zg); endif endfunction signal-1.4.5/inst/bitrevorder.m0000644000000000000000000000370314456505401014655 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## Copyright (C) 2013-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} bitrevorder (@var{x}) ## @deftypefnx {Function File} {[@var{y} @var{i}] =} bitrevorder (@var{x}) ## Reorder the elements of the vector @var{x} in bit-reversed order. ## Equivalent to calling @code{digitrevorder (@var{x}, 2)}. ## @seealso{digitrevorder, fft, ifft} ## @end deftypefn function [y, i] = bitrevorder (x) if (nargin != 1) print_usage (); elseif (! isvector (x)) error ("bitrevorder: X must be a vector"); elseif (fix (log2 (numel (x))) != log2 (numel (x))) error ("bitrevorder: X must have length equal to an integer power of 2"); endif [y, i] = digitrevorder (x, 2); endfunction %!assert (bitrevorder (0), 0); %!assert (bitrevorder (0:1), 0:1); %!assert (bitrevorder ([0:1]'), [0:1]'); %!assert (bitrevorder (0:7), [0 4 2 6 1 5 3 7]); %!assert (bitrevorder ([0:7]'), [0 4 2 6 1 5 3 7]'); %!assert (bitrevorder ([0:7]*i), [0 4 2 6 1 5 3 7]*i); %!assert (bitrevorder ([0:7]'*i), [0 4 2 6 1 5 3 7]'*i); %!assert (bitrevorder (0:15), [0 8 4 12 2 10 6 14 1 9 5 13 3 11 7 15]); %% Test input validation %!error bitrevorder (); %!error bitrevorder (1, 2); %!error bitrevorder ([]); %!error bitrevorder (0:2); signal-1.4.5/inst/blackmanharris.m0000644000000000000000000000516714456505401015315 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} blackmanharris (@var{m}) ## @deftypefnx {Function File} {} blackmanharris (@var{m}, "periodic") ## @deftypefnx {Function File} {} blackmanharris (@var{m}, "symmetric") ## Return the filter coefficients of a Blackman-Harris window of length @var{m}. ## ## If the optional argument @code{"periodic"} is given, the periodic form ## of the window is returned. This is equivalent to the window of length ## @var{m}+1 with the last coefficient removed. The optional argument ## @code{"symmetric"} is equivalent to not specifying a second argument. ## ## @seealso{rectwin, bartlett} ## @end deftypefn function w = blackmanharris (m, opt) if (nargin < 1 || nargin > 2) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("blackmanharris: M must be a positive integer"); endif N = m - 1; if (nargin == 2) switch (opt) case "periodic" N = m; case "symmetric" N = m - 1; otherwise error ("blackmanharris: window type must be either \"periodic\" or \"symmetric\""); endswitch endif if (m == 1) w = 1; else a0 = 0.35875; a1 = 0.48829; a2 = 0.14128; a3 = 0.01168; n = [0:m-1]'; w = a0 - a1.*cos(2.*pi.*n./N) + a2.*cos(4.*pi.*n./N) - a3.*cos(6.*pi.*n./N); endif endfunction %!assert (blackmanharris (1), 1); %!assert (blackmanharris (2), 0.00006 * ones (2, 1), eps); %!assert (blackmanharris (15), flipud (blackmanharris (15)), 10*eps); %!assert (blackmanharris (16), flipud (blackmanharris (16)), 10*eps); %!assert (blackmanharris (15), blackmanharris (15, "symmetric")); %!assert (blackmanharris (16)(1:15), blackmanharris (15, "periodic")); %% Test input validation %!error blackmanharris () %!error blackmanharris (0.5) %!error blackmanharris (-1) %!error blackmanharris (ones (1, 4)) %!error blackmanharris (1, 2) %!error blackmanharris (1, "invalid") signal-1.4.5/inst/blackmannuttall.m0000644000000000000000000000523014456505401015477 0ustar0000000000000000## Copyright (C) 2007 Muthiah Annamalai ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} blackmannuttall (@var{m}) ## @deftypefnx {Function File} {} blackmannuttall (@var{m}, "periodic") ## @deftypefnx {Function File} {} blackmannuttall (@var{m}, "symmetric") ## Return the filter coefficients of a Blackman-Nuttall window of length ## @var{m}. ## ## If the optional argument @code{"periodic"} is given, the periodic form ## of the window is returned. This is equivalent to the window of length ## @var{m}+1 with the last coefficient removed. The optional argument ## @code{"symmetric"} is equivalent to not specifying a second argument. ## ## @seealso{nuttallwin, kaiser} ## @end deftypefn function w = blackmannuttall (m, opt) if (nargin < 1 || nargin > 2) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("blackmannuttall: M must be a positive integer"); endif N = m - 1; if (nargin == 2) switch (opt) case "periodic" N = m; case "symmetric" N = m - 1; otherwise error ("blackmannuttall: window type must be either \"periodic\" or \"symmetric\""); endswitch endif if (m == 1) w = 1; else a0 = 0.3635819; a1 = 0.4891775; a2 = 0.1365995; a3 = 0.0106411; n = [0:m-1]'; w = a0 - a1.*cos(2.*pi.*n./N) + a2.*cos(4.*pi.*n./N) - a3.*cos(6.*pi.*n./N); endif endfunction %!assert (blackmannuttall (1), 1) %!assert (blackmannuttall (2), 0.0003628 * ones (2, 1), eps) %!assert (blackmannuttall (15), flipud (blackmannuttall (15)), 10*eps); %!assert (blackmannuttall (16), flipud (blackmannuttall (16)), 10*eps); %!assert (blackmannuttall (15), blackmannuttall (15, "symmetric")); %!assert (blackmannuttall (16)(1:15), blackmannuttall (15, "periodic")); %% Test input validation %!error blackmannuttall () %!error blackmannuttall (0.5) %!error blackmannuttall (-1) %!error blackmannuttall (ones (1, 4)) %!error blackmannuttall (1, 2) %!error blackmannuttall (1, "invalid") signal-1.4.5/inst/bohmanwin.m0000644000000000000000000000303014456505401014301 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} bohmanwin (@var{m}) ## Return the filter coefficients of a Bohman window of length @var{m}. ## @seealso{rectwin, bartlett} ## @end deftypefn function w = bohmanwin (m) if (nargin != 1) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("bohmanwin: M must be a positive integer"); endif if (m == 1) w = 1; else N = m - 1; n = -N/2:N/2; w = (1-2.*abs(n)./N).*cos(2.*pi.*abs(n)./N) + (1./pi).*sin(2.*pi.*abs(n)./N); w(1) = 0; w(length(w))=0; w = w'; endif endfunction %!assert (bohmanwin (1), 1) %!assert (bohmanwin (2), zeros (2, 1)) %% Test input validation %!error bohmanwin () %!error bohmanwin (0.5) %!error bohmanwin (-1) %!error bohmanwin (ones (1, 4)) %!error bohmanwin (1, 2) signal-1.4.5/inst/boxcar.m0000644000000000000000000000250314456505401013601 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} boxcar (@var{m}) ## Return the filter coefficients of a rectangular window of length @var{m}. ## @end deftypefn function w = boxcar (m) if (nargin != 1) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("boxcar: M must be a positive integer"); endif w = ones(m, 1); endfunction %!assert (boxcar (1), 1) %!assert (boxcar (2), ones (2, 1)) %!assert (boxcar (100), ones (100, 1)) %% Test input validation %!error boxcar () %!error boxcar (0.5) %!error boxcar (-1) %!error boxcar (ones (1, 4)) %!error boxcar (1, 2) signal-1.4.5/inst/buffer.m0000644000000000000000000002021014456505401013567 0ustar0000000000000000## Copyright (C) 2008-2022 David Bateman ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} buffer (@var{x}, @var{n}, @var{p}, @var{opt}) ## @deftypefnx {Function File} {[@var{y}, @var{z}, @var{opt}] =} buffer (@dots{}) ## Buffer a signal into a data frame. The arguments to @code{buffer} are ## ## @table @asis ## @item @var{x} ## The data to be buffered. ## ## @item @var{n} ## The number of rows in the produced data buffer. This is an positive ## integer value and must be supplied. ## ## @item @var{p} ## An integer less than @var{n} that specifies the under- or overlap ## between column in the data frame. The default value of @var{p} is 0. ## ## @item @var{opt} ## In the case of an overlap, @var{opt} can be either a vector of length ## @var{p} or the string 'nodelay'. If @var{opt} is a vector, then the ## first @var{p} entries in @var{y} will be filled with these values. If ## @var{opt} is the string 'nodelay', then the first value of @var{y} ## corresponds to the first value of @var{x}. ## ## In the can of an underlap, @var{opt} must be an integer between 0 and ## @code{-@var{p}}. The represents the initial underlap of the first ## column of @var{y}. ## ## The default value for @var{opt} the vector @code{zeros (1, @var{p})} ## in the case of an overlap, or 0 otherwise. ## @end table ## ## In the case of a single output argument, @var{y} will be padded with ## zeros to fill the missing values in the data frame. With two output ## arguments @var{z} is the remaining data that has not been used in the ## current data frame. ## ## Likewise, the output @var{opt} is the overlap, or underlap that might ## be used for a future call to @code{code} to allow continuous buffering. ## @end deftypefn function [y, z, opt] = buffer (x, n, p, opt) if (nargin < 2 || nargin > 4) print_usage (); endif if (!isscalar (n) || n != floor (n)) error ("buffer: n must be an integer"); endif if (nargin < 3) p = 0; elseif (!isscalar (p) || p != floor (p) || p >= n) error ("buffer: p must be an integer less than n"); endif if (nargin < 4) if (p < 0) opt = 0; else opt = zeros (1, p); endif endif if (rows (x) == 1) isrowvec = true; else isrowvec = false; endif if (p < 0) if (isscalar (opt) && opt == floor (opt) && opt >= 0 && opt <= -p) lopt = opt; else error ("buffer: expecting fourth argument to be and integer between 0 and -p"); endif else lopt = 0; endif x = x (:); l = length (x); m = ceil ((l - lopt) / (n - p)); y = zeros (n - p, m); y (1 : l - lopt) = x (lopt + 1 : end); if (p < 0) y (end + p + 1 : end, :) = []; elseif (p > 0) if (ischar (opt)) if (strcmp (opt, "nodelay")) y = [y ; zeros(p, m)]; if (p > n / 2) is = n - p + 1; in = n - p; ie = is + in - 1; off = 1; while (in > 0) y (is : ie, 1 : end - off) = y (1 : in, 1 + off : end); off++; is = ie + 1; ie = ie + in; if (ie > n) ie = n; endif in = ie - is + 1; endwhile [i, j] = ind2sub([n-p, m], l); if (all ([i, j] == [n-p, m])) off--; endif y (:, end - off + 2 : end) = []; else y (end - p + 1 : end, 1 : end - 1) = y (1 : p, 2 : end); if (sub2ind([n-p, m], p, m) >= l) y (:, end) = []; endif endif else error ("buffer: unexpected string argument"); endif elseif (isvector (opt)) if (length (opt) == p) lopt = p; y = [zeros(p, m); y]; in = p; off = 1; out = 1; while (in > 0) y(1:in, off) = opt(out:end); off++; in -= n - p; out += n - p; endwhile if (p > n / 2) in = n - p; ie = p; is = p - in + 1; off = 1; while (ie > 0) y (is : ie, 1 + off : end) = ... y (end - in + 1 : end, 1 : end - off); off++; ie = is - 1; is = is - in; if (is < 1) is = 1; endif in = ie - is + 1; endwhile else y (1 : p, 2 : end) = y (end - p + 1 : end, 1 : end - 1); endif else error ("buffer: opt vector must be of length p"); endif else error ("buffer: unrecognized fourth argument"); endif endif if (nargout > 1) if (p >= 0) [i, j] = ind2sub (size(y), l + lopt + p * (size (y, 2) - 1)); if (any ([i, j] != size (y))) z = y (1 + p : i, end); y (:, end) = []; else z = zeros (0, 1); endif else [i, j] = ind2sub (size (y) + [-p, 0], l - lopt); if (i < size (y, 1)) z = y (1: i, end); y (:, end) = []; else z = zeros (0, 1); endif endif if (isrowvec) z = z.'; endif if (p < 0) opt = max(0, size (y, 2) * (n - p) + opt - l); elseif (p > 0) opt = y(end-p+1:end)(:); else opt = []; endif endif endfunction %!error (buffer(1:10, 4.1)) %!assert (buffer(1:10, 4), reshape([1:10,0,0],[4,3])) %!assert (buffer(1:10, 4, 1), reshape([0:3,3:6,6:9,9,10,0,0],[4,4])) %!assert (buffer(1:10, 4, 2), reshape ([0,0:2,1:4,3:6,5:8,7:10],[4,5])) %!assert (buffer(1:10, 4, 3), [0,0,0:7;0,0:8;0:9;1:10]) %!error (buffer(1:10, 4, 3.1)) %!error (buffer(1:10, 4, 4)) %!assert (buffer(1:10, 4, -1), reshape([1:4,6:9],[4,2])) %!assert (buffer(1:10, 4, -2), reshape([1:4,7:10],[4,2])) %!assert (buffer(1:10, 4, -3), reshape([1:4,8:10,0],[4,2])) %!assert (buffer(1:10, 4, 1, 11), reshape([11,1:3,3:6,6:9,9,10,0,0],[4,4])) %!error (buffer(1:10, 4, 1, [10,11])) %!assert (buffer(1:10, 4, 1, 'nodelay'), reshape([1:4,4:7,7:10],[4,3])) %!error (buffer(1:10, 4, 1, 'badstring')) %!assert (buffer(1:10, 4, 2,'nodelay'), reshape ([1:4,3:6,5:8,7:10],[4,4])) %!assert (buffer(1:10, 4, 3, [11,12,13]),[11,12,13,1:7;12,13,1:8;13,1:9;1:10]) %!assert (buffer(1:10, 4, 3, 'nodelay'),[1:8;2:9;3:10;4:10,0]) %!assert (buffer(1:11,4,-2,1),reshape([2:5,8:11],4,2)) %!test %! [y, z] = buffer(1:12,4); %! assert (y, reshape(1:12,4,3)); %! assert (z, zeros (1,0)); %!test %! [y, z] = buffer(1:11,4); %! assert (y, reshape(1:8,4,2)); %! assert (z, [9, 10, 11]); %!test %! [y, z] = buffer([1:12]',4); %! assert (y, reshape(1:12,4,3)); %! assert (z, zeros (0,1)); %!test %! [y, z] = buffer([1:11]',4); %! assert (y, reshape(1:8,4,2)); %! assert (z, [9; 10; 11]); %!test %! [y,z,opt] = buffer(1:15,4,-2,1); %! assert (y, reshape([2:5,8:11],4,2)); %! assert (z, [14, 15]); %! assert (opt, 0); %!test %! [y,z,opt] = buffer(1:11,4,-2,1); %! assert (y, reshape([2:5,8:11],4,2)); %! assert (z, zeros (1,0)); %! assert (opt, 2); %!test %! [y,z,opt] = buffer([1:15]',4,-2,1); %! assert (y, reshape([2:5,8:11],4,2)); %! assert (z, [14; 15]); %! assert (opt, 0); %!test %! [y,z,opt] = buffer([1:11]',4,-2,1); %! assert (y, reshape([2:5,8:11],4,2)); %! assert (z, zeros (0, 1)); %! assert (opt, 2); %!test %! [y,z,opt] = buffer([1:11],5,2,[-1,0]); %! assert (y, reshape ([-1:3,2:6,5:9],[5,3])); %! assert (z, [10, 11]); %! assert (opt, [8; 9]); %!test %! [y,z,opt] = buffer([1:11]',5,2,[-1,0]); %! assert (y, reshape ([-1:3,2:6,5:9],[5,3])); %! assert (z, [10; 11]); %! assert (opt, [8; 9]); %!test %! [y, z, opt] = buffer (1:10, 6, 4); %! assert (y, [0 0 1:2:5; 0 0 2:2:6; 0 1:2:7; 0 2:2:8; 1:2:9; 2:2:10]) %! assert (z, zeros (1, 0)) %! assert (opt, [7; 8; 9; 10]) signal-1.4.5/inst/buttap.m0000644000000000000000000000241114456505401013620 0ustar0000000000000000## Copyright (C) 2013 CarnĂ« Draug ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} buttap (@var{n}) ## Design lowpass analog Butterworth filter. ## ## This function exists for @sc{matlab} compatibility only, and is equivalent ## to @code{butter (@var{n}, 1, "s")}. ## ## @seealso{butter} ## @end deftypefn function [z, p, g] = buttap (n) if (nargin != 1) print_usage(); elseif (! isscalar (n) || ! isnumeric (n) || fix (n) != n || n <= 0) error ("buttap: N must be a positive integer") endif [z, p, g] = butter (n, 1, "s"); endfunction signal-1.4.5/inst/butter.m0000644000000000000000000002233114456505401013631 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## Copyright (C) 2003 Doug Stewart ## Copyright (C) 2011 Alexander Klein ## Copyright (C) 2018 John W. Eaton ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{b}, @var{a}] =} butter (@var{n}, @var{wc}) ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} butter (@var{n}, @var{wc}, @var{filter_type}) ## @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} butter (@dots{}) ## @deftypefnx {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} butter (@dots{}) ## @deftypefnx {Function File} {[@dots{}] =} butter (@dots{}, "s") ## Generate a Butterworth filter. ## Default is a discrete space (Z) filter. ## ## The cutoff frequency, @var{wc} should be specified in radians for ## analog filters. For digital filters, it must be a value between zero ## and one. For bandpass filters, @var{wc} is a two-element vector ## with @code{w(1) < w(2)}. ## ## The filter type must be one of @qcode{"low"}, @qcode{"high"}, ## @qcode{"bandpass"}, or @qcode{"stop"}. The default is @qcode{"low"} ## if @var{wc} is a scalar and @qcode{"bandpass"} if @var{wc} is a ## two-element vector. ## ## If the final input argument is @qcode{"s"} design an analog Laplace ## space filter. ## ## Low pass filter with cutoff @code{pi*Wc} radians: ## ## @example ## [b, a] = butter (n, Wc) ## @end example ## ## High pass filter with cutoff @code{pi*Wc} radians: ## ## @example ## [b, a] = butter (n, Wc, "high") ## @end example ## ## Band pass filter with edges @code{pi*Wl} and @code{pi*Wh} radians: ## ## @example ## [b, a] = butter (n, [Wl, Wh]) ## @end example ## ## Band reject filter with edges @code{pi*Wl} and @code{pi*Wh} radians: ## ## @example ## [b, a] = butter (n, [Wl, Wh], "stop") ## @end example ## ## Return filter as zero-pole-gain rather than coefficients of the ## numerator and denominator polynomials: ## ## @example ## [z, p, g] = butter (@dots{}) ## @end example ## ## Return a Laplace space filter, @var{Wc} can be larger than 1: ## ## @example ## [@dots{}] = butter (@dots{}, "s") ## @end example ## ## Return state-space matrices: ## ## @example ## [a, b, c, d] = butter (@dots{}) ## @end example ## ## References: ## ## Proakis & Manolakis (1992). Digital Signal Processing. New York: ## Macmillan Publishing Company. ## @end deftypefn function [a, b, c, d] = butter (n, wc, varargin) if (nargin > 4 || nargin < 2 || nargout > 4) print_usage (); endif type = "lowpass"; stop = false; digital = true; if (! (isscalar (n) && (n == fix (n)) && (n > 0))) error ("butter: filter order N must be a positive integer"); endif if (! isvector (wc) || numel (wc) > 2) error ("butter: cutoff frequency must be given as WC or [WL, WH]"); endif if (numel (wc) == 2) if (wc(1) > wc(2)) error ("butter: W(1) must be less than W(2)"); endif type = "bandpass"; stop = false; endif ## Is final argument "s" (or "z")? if (numel (varargin) > 0) switch (varargin{end}) case "s" digital = false; varargin(end) = []; case "z" ## This is the default setting. ## Accept "z" for backward compatibility with older versions ## of Octave's signal processing package. varargin(end) = []; endswitch endif ## Is filter type specified? if (numel (varargin) > 0) switch (varargin{end}) case {"high", "stop"} type = varargin{end}; stop = true; varargin(end) = []; case {"low", "bandpass"} type = varargin{end}; stop = false; varargin(end) = []; case "pass" ## Accept "pass" for backward compatibility with older versions ## of Octave's signal processing package. type = "bandpass"; stop = false; varargin(end) = []; otherwise error ("butter: expected 'high', 'stop', 'low', 'bandpass', or 's'"); endswitch endif if (numel (varargin) > 0) ## Invalid arguments. For example: butter (n, wc, "s", "high"). print_usage (); endif switch (type) case {"stop", "bandpass"} if (numel (wc) != 2) error ("butter: Wc must be two elements for stop and bandpass filters"); endif endswitch if (digital && ! all ((wc >= 0) & (wc <= 1))) error ("butter: all elements of Wc must be in the range [0,1]"); elseif (! digital && ! all (wc >= 0)) error ("butter: all elements of Wc must be in the range [0,inf]"); endif ## Prewarp to the band edges to s plane if (digital) T = 2; # sampling frequency of 2 Hz wc = 2 / T * tan (pi * wc / T); endif ## Generate splane poles for the prototype Butterworth filter ## source: Kuc C = 1; ## default cutoff frequency pole = C * exp (1i * pi * (2 * [1:n] + n - 1) / (2 * n)); if (mod (n, 2) == 1) pole((n + 1) / 2) = -1; ## pure real value at exp(i*pi) endif zero = []; gain = C^n; ## splane frequency transform [zero, pole, gain] = sftrans (zero, pole, gain, wc, stop); ## Use bilinear transform to convert poles to the z plane if (digital) [zero, pole, gain] = bilinear (zero, pole, gain, T); endif ## convert to the correct output form ## note that poly always outputs a row vector if (nargout <= 2) a = real (gain * poly (zero)); b = real (poly (pole)); elseif (nargout == 3) a = zero(:); b = pole(:); c = gain; else ## output ss results [a, b, c, d] = zp2ss (zero, pole, gain); endif endfunction %!shared sf, sf2, off_db %! off_db = 0.5; %! ## Sampling frequency must be that high to make the low pass filters pass. %! sf = 6000; sf2 = sf/2; %! data=[sinetone(5,sf,10,1),sinetone(10,sf,10,1),sinetone(50,sf,10,1),sinetone(200,sf,10,1),sinetone(400,sf,10,1)]; %!test %! ## Test low pass order 1 with 3dB @ 50Hz %! data=[sinetone(5,sf,10,1),sinetone(10,sf,10,1),sinetone(50,sf,10,1),sinetone(200,sf,10,1),sinetone(400,sf,10,1)]; %! [b, a] = butter ( 1, 50 / sf2 ); %! filtered = filter ( b, a, data ); %! damp_db = 20 * log10 ( max ( filtered ( end - sf : end, : ) ) ); %! assert ( [ damp_db( 4 ) - damp_db( 5 ), damp_db( 1 : 3 ) ], [ 6 0 0 -3 ], off_db ) %!test %! ## Test low pass order 4 with 3dB @ 50Hz %! data=[sinetone(5,sf,10,1),sinetone(10,sf,10,1),sinetone(50,sf,10,1),sinetone(200,sf,10,1),sinetone(400,sf,10,1)]; %! [b, a] = butter ( 4, 50 / sf2 ); %! filtered = filter ( b, a, data ); %! damp_db = 20 * log10 ( max ( filtered ( end - sf : end, : ) ) ); %! assert ( [ damp_db( 4 ) - damp_db( 5 ), damp_db( 1 : 3 ) ], [ 24 0 0 -3 ], off_db ) %!test %! ## Test high pass order 1 with 3dB @ 50Hz %! data=[sinetone(5,sf,10,1),sinetone(10,sf,10,1),sinetone(50,sf,10,1),sinetone(200,sf,10,1),sinetone(400,sf,10,1)]; %! [b, a] = butter ( 1, 50 / sf2, "high" ); %! filtered = filter ( b, a, data ); %! damp_db = 20 * log10 ( max ( filtered ( end - sf : end, : ) ) ); %! assert ( [ damp_db( 2 ) - damp_db( 1 ), damp_db( 3 : end ) ], [ 6 -3 0 0 ], off_db ) %!test %! ## Test high pass order 4 with 3dB @ 50Hz %! data=[sinetone(5,sf,10,1),sinetone(10,sf,10,1),sinetone(50,sf,10,1),sinetone(200,sf,10,1),sinetone(400,sf,10,1)]; %! [b, a] = butter ( 4, 50 / sf2, "high" ); %! filtered = filter ( b, a, data ); %! damp_db = 20 * log10 ( max ( filtered ( end - sf : end, : ) ) ); %! assert ( [ damp_db( 2 ) - damp_db( 1 ), damp_db( 3 : end ) ], [ 24 -3 0 0 ], off_db ) %% Test input validation %!error [a, b] = butter () %!error [a, b] = butter (1) %!error [a, b] = butter (1, 2, 3, 4, 5) %!error [a, b] = butter (.5, .2) %!error [a, b] = butter (3, .2, "invalid") %!error [a, b] = butter (9, .6, "stop") %!error [a, b] = butter (9, .6, "bandpass") %!error [a, b] = butter (9, .6, "s", "high") %% Test output orientation %!test %! butter (9, .6); %! assert (isrow (ans)); %!test %! A = butter (9, .6); %! assert (isrow (A)); %!test %! [A, B] = butter (9, .6); %! assert (isrow (A)); %! assert (isrow (B)); %!test %! [z, p, g] = butter (9, .6); %! assert (iscolumn (z)); %! assert (iscolumn (p)); %! assert (isscalar (g)); %!test %! [a, b, c, d] = butter (9, .6); %! assert (ismatrix (a)); %! assert (iscolumn (b)); %! assert (isrow (c)); %! assert (isscalar (d)); %!demo %! sf = 800; sf2 = sf/2; %! data=[[1;zeros(sf-1,1)],sinetone(25,sf,1,1),sinetone(50,sf,1,1),sinetone(100,sf,1,1)]; %! [b,a]=butter ( 1, 50 / sf2 ); %! filtered = filter(b,a,data); %! %! clf %! subplot ( columns ( filtered ), 1, 1) %! plot(filtered(:,1),";Impulse response;") %! subplot ( columns ( filtered ), 1, 2 ) %! plot(filtered(:,2),";25Hz response;") %! subplot ( columns ( filtered ), 1, 3 ) %! plot(filtered(:,3),";50Hz response;") %! subplot ( columns ( filtered ), 1, 4 ) %! plot(filtered(:,4),";100Hz response;") signal-1.4.5/inst/buttord.m0000644000000000000000000011610614456505401014013 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## Copyright (C) 2018 Charles Praplan ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{n} =} buttord (@var{wp}, @var{ws}, @var{rp}, @var{rs}) ## @deftypefnx {Function File} {@var{n} =} buttord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}) ## @deftypefnx {Function File} {@var{n} =} buttord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}, "s") ## @deftypefnx {Function File} {[@var{n}, @var{wc_p}] =} buttord (@dots{}) ## @deftypefnx {Function File} {[@var{n}, @var{wc_p}, @var{wc_s}] =} buttord (@dots{}) ## Compute the minimum filter order of a Butterworth filter with the desired ## response characteristics. The filter frequency band edges are specified by ## the passband frequency @var{wp} and stopband frequency @var{ws}. Frequencies ## are normalized to the Nyquist frequency in the range [0,1]. @var{rp} is the ## allowable passband ripple measured in decibels, and @var{rs} is the minimum ## attenuation in the stop band, also in decibels. ## ## The output arguments @var{n} and @var{wc_p} (or @var{n} and @var{wc_n}) can ## be given as inputs to @code{butter}. ## Using @var{wc_p} makes the filter characteristic touch at least one pass band ## corner and using @var{wc_s} makes the characteristic touch at least one ## stop band corner. ## ## If @var{wp} and @var{ws} are scalars, then @var{wp} is the passband cutoff ## frequency and @var{ws} is the stopband edge frequency. If @var{ws} is ## greater than @var{wp}, the filter is a low-pass filter. If @var{wp} is ## greater than @var{ws}, the filter is a high-pass filter. ## ## If @var{wp} and @var{ws} are vectors of length 2, then @var{wp} defines the ## passband interval and @var{ws} defines the stopband interval. If @var{wp} ## is contained within @var{ws} (@var{ws1} < @var{wp1} < @var{wp2} < @var{ws2}), ## the filter is a band-pass filter. If @var{ws} is contained within @var{wp} ## (@var{wp1} < @var{ws1} < @var{ws2} < @var{wp2}), the filter is a band-stop ## or band-reject filter. ## ## If the optional argument @code{"s"} is given, the minimum order for an analog ## elliptic filter is computed. All frequencies @var{wp} and @var{ws} are ## specified in radians per second. ## ## Theory: For Low pass filters, |H(W)|^2 = 1/[1+(W/Wc)^(2N)] = 10^(-R/10). ## With some algebra, you can solve simultaneously for Wc and N given ## Ws,Rs and Wp,Rp. Rounding N to the next greater integer, one can recalculate ## the allowable range for Wc (filter caracteristic touching the pass band edge ## or the stop band edge). ## ## For other types of filter, before making the above calculation, the ## requirements must be transformed to LP requirements. After calculation, Wc ## must be transformed back to original filter type. ## @seealso{butter, cheb1ord, cheb2ord, ellipord} ## @end deftypefn function [n, Wc_p, Wc_s] = buttord (Wp, Ws, Rp, Rs, opt) if (nargin < 4 || nargin > 5) print_usage (); elseif (nargin == 5 && ! strcmp (opt, "s")) error ("ellipord: OPT must be the string \"s\""); endif if (nargin == 5 && strcmp (opt, "s")) s_domain = true; else s_domain = false; endif if (s_domain) validate_filter_bands ("buttord", Wp, Ws, "s"); else validate_filter_bands ("buttord", Wp, Ws); endif if (s_domain) # No prewarp in case of analog filter Wpw = Wp; Wsw = Ws; else ## sampling frequency of 2 Hz T = 2; Wpw = (2 / T) .* tan (pi .* Wp ./ T); # prewarp Wsw = (2 / T) .* tan (pi .* Ws ./ T); # prewarp endif ## pass/stop band to low pass filter transform: if (length (Wpw) == 2 && length (Wsw) == 2) ## Band-pass filter if (Wpw(1) > Wsw(1)) ## Modify band edges if not symmetrical. For a band-pass filter, ## the lower or upper stopband limit is moved, resulting in a smaller ## stopband than the caller requested. if (Wpw(1) * Wpw(2) < Wsw(1) * Wsw(2)) Wsw(2) = Wpw(1) * Wpw(2) / Wsw(1); else Wsw(1) = Wpw(1) * Wpw(2) / Wsw(2); endif w02 = Wpw(1) * Wpw(2); wp = Wpw(2) - Wpw(1); ws = Wsw(2) - Wsw(1); ## Band-stop / band-reject / notch filter else ## Modify band edges if not symmetrical. For a band-stop filter, ## the lower or upper passband limit is moved, resulting in a smaller ## rejection band than the caller requested. if (Wpw(1) * Wpw(2) > Wsw(1) * Wsw(2)) Wpw(2) = Wsw(1) * Wsw(2) / Wpw(1); else Wpw(1) = Wsw(1) * Wsw(2) / Wpw(2); endif w02 = Wpw(1) * Wpw(2); wp = w02 / (Wpw(2) - Wpw(1)); ws = w02 / (Wsw(2) - Wsw(1)); endif ws = ws / wp; wp = 1; ## High-pass filter elseif (Wpw > Wsw) wp = Wsw; ws = Wpw; ## Low-pass filter else wp = Wpw; ws = Wsw; endif ## compute minimum n which satisfies all band edge conditions qs = log (10 ^ (Rs / 10) - 1); qp = log (10 ^ (Rp / 10) - 1); n = ceil (max (0.5 * (qs - qp) ./ log (ws./wp))); ## compute -3dB cutoff given Wp, Rp and n if (length (Wpw) == 2 && length (Wsw) == 2) ## Band-pass filter if (Wpw(1) > Wsw(1)) w_prime_p = exp (log (Wpw) - qp / 2 / n); # same formula as for LP w_prime_s = exp (log (Wsw) - qs / 2 / n); # " ## Band-stop / band-reject / notch filter else w_prime_p = exp( log (Wpw) + qp / 2 / n); # same formula as for HP w_prime_s = exp( log (Wsw) + qs / 2 / n); # " endif ## Applying LP to BP (respectively HP to notch) transformation to -3dB ## angular frequency : ## s_prime/wc = Q(s/w0+w0/s) or w_prime/wc = Q(w/w0-w0/w) ## Here we need to inverse above equation: ## w = abs(w_prime+-sqrt(w_prime^2+4*Q^2))/(2*Q/w0); ## -3dB cutoff freq to match pass band w0 = sqrt (prod (Wpw)); Q = w0 / diff (Wpw); # BW at -Rp dB not at -3dB wc = Wpw; W_prime = w_prime_p(1) / wc(1); # same with w_prime(2)/wc(2) wa = abs (W_prime + sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); wb = abs (W_prime - sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); Wcw_p = [wb wa]; ## -3dB cutoff freq to match stop band w0 = sqrt (prod (Wsw)); Q = w0 / diff (Wsw); # BW at -Rs dB not at -3dB wc = Wsw; W_prime = w_prime_s(1) / wc(1); # same with w_prime(2)/wc(2) wa =abs (W_prime + sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); wb =abs (W_prime - sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); Wcw_s = [wb wa]; ## High-pass filter elseif (Wpw > Wsw) ## -3dB cutoff freq to match pass band Wcw_p = exp (log (Wpw) + qp / 2 / n); ## -3dB cutoff freq to match stop band Wcw_s = exp (log (Wsw) + qs / 2 / n); ## Low-pass filter else ## -3dB cutoff freq to match pass band Wcw_p = exp (log (Wpw) - qp / 2 / n); ## -3dB cutoff freq to match stop band Wcw_s = exp( log (Wsw) - qs / 2 / n); endif if (s_domain) # No prewarp in case of analog filter Wc_p = Wcw_p; Wc_s = Wcw_s; else # Inverse frequency warping for discrete-time filter Wc_p = atan (Wcw_p .* (T / 2)) .* (T / pi); Wc_s = atan (Wcw_s .* (T / 2)) .* (T / pi); endif endfunction %!demo %! fs = 44100; %! Npts = fs / 2; %! fpass = 4000; %! fstop = 10987; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_p); %! f = 8000:12000; %! W = 2 * pi * f; %! [H, f] = freqz (b, a, Npts, fs); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth low-pass : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! Npts = fs / 2; %! fpass = 4000; %! fstop = 10987; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_s); %! f = 8000:12000; %! W = 2 * pi * f; %! [H, f] = freqz (b, a, Npts, fs); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth low-pass : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! Npts = fs / 2; %! fstop = 4000; %! fpass = 10987; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_p, "high"); %! f = 8000:12000; %! W = 2 * pi * f; %! [H, f] = freqz (b, a, Npts, fs); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth high-pass : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [min(f) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! Npts = fs / 2; %! fstop = 4000; %! fpass = 10987; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_s, "high"); %! f = 8000:12000; %! W = 2 * pi * f; %! [H, f] = freqz (b, a, Npts, fs); %! plot (f, 20 * log10 (abs (H))) %! title ("Digital Butterworth high-pass : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [min(f) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [8500 10051]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_p); %! f = (8000:12000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth band-pass : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on; %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [8500 10051]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_s); %! f = (8000:12000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth band-pass : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on; %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [9204 10700]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_p); %! f = (8000:12000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth band-pass : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on; %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [9204 10700]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_s); %! f = (8000:12000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth band-pass : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on; %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [8500 10833]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_p, "stop"); %! f = (8000:12000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth notch : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , ... %! 0 , 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [8500 10833]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_s, "stop"); %! f = (8000:12000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth notch : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , ... %! 0 , 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [9183 11000]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_p, "stop"); %! f = (8000:12000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth notch : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , ... %! 0 , 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [9183 11000]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = butter (n, Wn_s, "stop"); %! f = (8000:12000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Butterworth notch : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , ... %! 0 , 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = 4000; %! fstop = 13583; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_p, "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))) %! title ("Analog Butterworth low-pass : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = 4000; %! fstop = 13583; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_s, "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth low-pass : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = 4000; %! fpass = 13583; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_p, "high", "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth high-pass : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = 4000; %! fpass = 13583; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_s, "high", "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth high-pass : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9000, 10436]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_p, "s"); %! f = 8000:12000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth band-pass : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on; %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9000, 10436]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_s, "s"); %! f = 8000:12000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth band-pass : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on; %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9582, 11000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_p, "s"); %! f = 8000:12000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth band-pass : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on; %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9582, 11000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_s, "s"); %! f = 8000:12000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth band-pass : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on; %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = [9875 10126.5823]; %! fpass = [9000 10436]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_p, "stop", "s"); %! f = 8000:12000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth notch : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , ... %! 0 , 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = [9875 10126.5823]; %! fpass = [9000 10436]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_s, "stop", "s"); %! f = 8000:12000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth notch : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , ... %! 0 , 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = [9875 10126.5823]; %! fpass = [9582 11000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_p, "stop", "s"); %! f = 8000:12000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth notch : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , ... %! 0 , 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = [9875 10126.5823]; %! fpass = [9582 11000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = buttord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = butter (n, Wn_s, "stop", "s"); %! f = 8000:12000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Butterworth notch : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , ... %! 0 , 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!test %! # Analog band-pass %! [n, Wn_p, Wn_s] = buttord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9000, 10436], 1, 26, "s"); %! assert (n, 4); %! assert (round (Wn_p), [61903, 63775]); %! assert (round (Wn_s), [61575, 64114]); %!test %! # Analog band-pass %! [n, Wn_p, Wn_s] = buttord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9582, 11000], 1, 26, "s"); %! assert (n, 4); %! assert (round (Wn_p), [61903, 63775]); %! assert (round (Wn_s), [61575, 64115]); %!test %! # Analog band-pass %! [n, Wn_p, Wn_s] = buttord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9000, 10437], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [61850, 63830]); %! assert (round (Wn_s), [61848, 63831]); %!test %! # Analog band-pass %! [n, Wn_p, Wn_s] = buttord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9581, 11000], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [61850, 63830]); %! assert (round (Wn_s), [61847, 63832]); %!test %! # Analog high-pass %! [n, Wn_p, Wn_s] = buttord (2 * pi * 13583, 2 * pi * 4000, 1, 26, "s"); %! assert (n, 4); %! assert (round (Wn_p), 72081); %! assert (round (Wn_s), 53101); %!test %! # Analog high-pass %! [n, Wn_p, Wn_s] = buttord (2 * pi * 13584, 2 * pi * 4000, 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), 68140); %! assert (round (Wn_s), 68138); %!test %! # Analog low-pass %! [n, Wn_p, Wn_s] = buttord (2 * pi * 4000, 2 * pi * 13583, 1, 26, "s"); %! assert (n, 4); %! assert (round (Wn_p), 29757); %! assert (round (Wn_s), 40394); %!test %! # Analog low-pass %! [n, Wn_p, Wn_s] = buttord (2 * pi * 4000, 2 * pi * 13584, 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), 31481); %! assert (round (Wn_s), 31482); %!test %! # Analog notch (narrow band-stop) %! [n, Wn_p, Wn_s] = buttord (2 * pi * [9000, 10436], ... %! 2 * pi * [9875, 10126.5823], 1, 26, "s"); %! assert (n, 4); %! assert (round (Wn_p), [60607, 65138]); %! assert (round (Wn_s), [61184, 64524]); %!test %! # Analog notch (narrow band-stop) %! [n, Wn_p, Wn_s] = buttord (2 * pi * [9582, 11000], ... %! 2 * pi * [9875, 10126.5823], 1, 26, "s"); %! assert (n, 4); %! assert (round (Wn_p), [60606, 65139]); %! assert (round (Wn_s), [61184, 64524]); %!test %! # Analog notch (narrow band-stop) %! [n, Wn_p, Wn_s] = buttord (2 * pi * [9000, 10437], ... %! 2 * pi * [9875, 10126.5823], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [60722, 65015]); %! assert (round (Wn_s), [60726, 65011]); %!test %! # Analog notch (narrow band-stop) %! [n, Wn_p, Wn_s] = buttord (2 * pi * [9581, 11000], ... %! 2 * pi * [9875, 10126.5823], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [60721, 65016]); %! assert (round (Wn_s), [60726, 65011]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * [9500, 9750], ... %! 2 / fs * [8500, 10051], 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 4); %! assert (round (Wn_p), [9477, 9773]); %! assert (round (Wn_s), [9425, 9826]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * [9500, 9750], ... %! 2 / fs * [9204, 10700], 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 4); %! assert (round (Wn_p), [9477, 9773]); %! assert (round (Wn_s), [9425, 9826]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * [9500, 9750], ... %! 2 / fs * [8500, 10052], 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9469, 9782]); %! assert (round (Wn_s), [9468, 9782]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * [9500, 9750], ... %! 2 / fs * [9203, 10700], 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9469, 9782]); %! assert (round (Wn_s), [9468, 9782]); %!test %! # Digital high-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * 10987, 2 / fs * 4000, 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 4); %! assert (round (Wn_p), 9808); %! assert (round (Wn_s), 7780); %!test %! # Digital high-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * 10988, 2 / fs * 4000, 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), 9421); %! assert (round (Wn_s), 9421); %!test %! # Digital low-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * 4000, 2 / fs * 10987, 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 4); %! assert (round (Wn_p), 4686); %! assert (round (Wn_s), 6176); %!test %! # Digital low-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * 4000, 2 / fs * 10988, 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), 4936); %! assert (round (Wn_s), 4936); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * [8500, 10833], ... %! 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 4); %! assert (round (Wn_p), [9369, 10640]); %! assert (round (Wn_s), [9605, 10400]); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * [9183, 11000], ... %! 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 4); %! assert (round (Wn_p), [9370, 10640]); %! assert (round (Wn_s), [9605, 10400]); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * [8500, 10834], ... %! 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9421, 10587]); %! assert (round (Wn_s), [9422, 10587]); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn_p, Wn_s] = buttord (2 / fs * [9182, 11000], ... %! 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9421, 10587]); %! assert (round (Wn_s), [9422, 10587]); ## Test input validation %!error buttord () %!error buttord (.1) %!error buttord (.1, .2) %!error buttord (.1, .2, 3) %!error buttord ([.1 .1], [.2 .2], 3, 4) %!error buttord ([.1 .2], [.5 .6], 3, 4) %!error buttord ([.1 .5], [.2 .6], 3, 4) signal-1.4.5/inst/cceps.m0000644000000000000000000000435614456505401013430 0ustar0000000000000000## Copyright (C) 1994 Dept of Probability Theory and Statistics TU Wien ## Copyright (C) 2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} cceps (@var{x}) ## @deftypefnx {Function File} {} cceps (@var{x}, @var{correct}) ## Return the complex cepstrum of the vector @var{x}. ## If the optional argument @var{correct} has the value 1, a correction ## method is applied. The default is not to do this. ## @end deftypefn function cep = cceps (x, c) if (nargin == 1) c = false; elseif (nargin != 2) print_usage (); endif [nr, nc] = size (x); if (nc != 1) if (nr == 1) x = x'; nr = nc; else error ("cceps: X must be a vector"); endif endif bad_signal_message = "cceps: signal X has some zero Fourier coefficients"; F = fft (x); if (min (abs (F)) == 0) error (bad_signal_message); endif ## determine if correction necessary half = fix (nr / 2); cor = false; if (2 * half == nr) cor = (c && (real (F (half + 1)) < 0)); if (cor) F = fft (x(1:nr-1)) if (min (abs (F)) == 0) error (bad_signal_message); endif endif endif cep = fftshift (ifft (log (F))); ## make result real if (c) cep = real (cep); if (cor) ## make cepstrum of same length as input vector cep (nr) = 0; endif endif endfunction %!test %! x = randn (256, 1); %! c = cceps (x); %! assert (size (c), size (x)) ## Test input validation %!error cceps () %!error cceps (1, 2, 3) %!error cceps (ones (4)) %!error cceps (0) %!error cceps (zeros (10, 1)) signal-1.4.5/inst/cconv.m0000644000000000000000000000701214456505401013433 0ustar0000000000000000## Copyright (C) 2018 Leonardo Araujo ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{c} =} cconv (@var{a}, @var{b}, @var{n}) ## @deftypefnx {Function File} {@var{c} =} cconv (@var{a}, @var{b}) ## Compute the modulo-N circular convolution. ## ## @var{a} and @var{b} are input vectors and @var{c} is the modolo-@var{n} ## convolution of @var{a} and @var{b}. If @var{n} is not provided, ## its assumed default value is @code{length(@var{a}) + length(@var{b}) - 1}, ## which provides the same result as a linear convolution. ## ## Examples: ## ## @example ## @group ## cconv (1:2, 1:4) ## @result{} 1 4 7 10 8 ## @end group ## @end example ## ## @example ## @group ## cconv (1:2, 1:4, 2) ## @result{} 16 14 ## @end group ## @end example ## ## @example ## @group ## cconv (1:2, 1:4, 4) ## @result{} 9 4 7 10 ## @end group ## @end example ## ## @seealso{conv, circshift} ## @end deftypefn function c = cconv (a, b, n) if (nargin < 2 || nargin > 3) print_usage (); endif la = length (a); lb = length (b); if (nargin == 3) if (! isscalar (n)) error ("cconv: N must be a scalar"); elseif (any (n != fix (n))) error ("cconv: N must be an integer"); endif else n = la + lb - 1; endif if (! isvector (a) || ! isvector (b)) error ("cconv: both arguments A and B must be vectors"); endif flgcolumn = false; if ((la > 1 && iscolumn (a)) || (lb > 1 && iscolumn (b))) flgcolumn = true; endif a = a(:); b = b(:); if (la < lb) a = [a; zeros(lb - la, 1)]; elseif (lb < la) b = [b; zeros(la - lb, 1)]; end N = length (a); if (n < N) an = zeros (n, 1); bn = zeros (n, 1); for i = 0 : N - 1, an(mod (i, n) + 1) += a(i + 1); bn(mod (i, n) + 1) += b(i + 1); endfor a = an; b = bn; elseif (n > N) a = [a; zeros(n - N, 1)]; b = [b; zeros(n - N, 1)]; endif c = ifft (fft (a) .* fft (b)) ; if (!flgcolumn) c = c.'; endif endfunction %!shared x %! x = [1, 2, 3, 4, 5]; %!assert (cconv (x, 1), [1, 2, 3, 4, 5], 2*eps) %!assert (cconv (x', 1), [1; 2; 3; 4; 5], 2*eps) %!assert (real (cconv (x, [1 1])), [1, 3, 5, 7, 9, 5], 2*eps) %!assert (cconv (x, [1 1], 3), [8, 12, 10]) %!assert (cconv ([2 1 2 1], [1 2 3 4]), [2 5 10 16 12 11 4], 1e-14) %!assert (cconv ([2 1 2 1], [1 2 3 4], 4), [14 16 14 16]) %!assert (cconv ([2 1 2 1], [1 2 3 4], 3), [22 17 21]) %!assert (cconv ([2 1 2 1], [1 2 3 4], 2), [28 32]) %!assert (cconv ([2 1 2 1], [1 2 3 4], 1), 60) %!assert (cconv (x*j, 1), [1j, 2j, 3j, 4j, 5j]) %!assert (cconv (x'*j, 1), [1j; 2j; 3j; 4j; 5j]) ## Test input validation %!error cconv () %!error cconv (1) %!error cconv (1, 1, [1 1]) %!error cconv (ones (2, 2), 1) %!error cconv (1, ones (2, 2)) %!error cconv (1, 1, 3.5) signal-1.4.5/inst/cheb.m0000644000000000000000000000327614456505401013234 0ustar0000000000000000## Copyright (C) 2002 AndrĂ© Carezia ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} cheb (@var{n}, @var{x}) ## Returns the value of the nth-order Chebyshev polynomial calculated at ## the point x. The Chebyshev polynomials are defined by the equations: ## ## @example ## @group ## / cos(n acos(x), |x| <= 1 ## Tn(x) = | ## \ cosh(n acosh(x), |x| > 1 ## @end group ## @end example ## ## If x is a vector, the output is a vector of the same size, where each ## element is calculated as y(i) = Tn(x(i)). ## @end deftypefn function T = cheb (n, x) if (nargin != 2) print_usage; elseif !(isscalar (n) && (n == round(n)) && (n >= 0)) error ("cheb: n has to be a positive integer"); endif if (max(size(x)) == 0) T = []; endif ## avoid resizing latencies T = zeros(size(x)); ind = abs (x) <= 1; if (max(size(ind))) T(ind) = cos(n*acos(x(ind))); endif ind = abs (x) > 1; if (max(size(ind))) T(ind) = cosh(n*acosh(x(ind))); endif T = real(T); endfunction signal-1.4.5/inst/cheb1ap.m0000644000000000000000000000263614456505401013635 0ustar0000000000000000## Copyright (C) 2013 CarnĂ« Draug ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} cheb1ap (@var{n}, @var{Rp}) ## Design lowpass analog Chebyshev type I filter. ## ## This function exists for @sc{matlab} compatibility only, and is equivalent ## to @code{cheby1 (@var{n}, @var{Rp}, 1, "s")}. ## ## @seealso{cheby1} ## @end deftypefn function [z, p, g] = cheb1ap (n, Rp) if (nargin != 2) print_usage(); elseif (! isscalar (n) || ! isnumeric (n) || fix (n) != n || n <= 0) error ("cheb1ap: N must be a positive integer") elseif (! isscalar (Rp) || ! isnumeric (Rp) || Rp < 0) error ("cheb1ap: RP must be a non-negative scalar") endif [z, p, g] = cheby1 (n, Rp, 1, "s"); endfunction signal-1.4.5/inst/cheb1ord.m0000644000000000000000000010704514456505401014021 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## Copyright (C) 2000 Laurent S. Mazet ## Copyright (C) 2018 Charles Praplan ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{n} =} cheb1ord (@var{wp}, @var{ws}, @var{rp}, @var{rs}) ## @deftypefnx {Function File} {@var{n} =} cheb1ord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}) ## @deftypefnx {Function File} {@var{n} =} cheb1ord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}, "s") ## @deftypefnx {Function File} {[@var{n}, @var{wc}] =} cheb1ord (@dots{}) ## @deftypefnx {Function File} {[@var{n}, @var{wc_p}, @var{wc_s}] =} cheb1ord (@dots{}) ## Compute the minimum filter order of a Chebyshev type I filter with the ## desired response characteristics. The filter frequency band edges are ## specified by the passband frequency @var{wp} and stopband frequency @var{ws}. ## Frequencies are normalized to the Nyquist frequency in the range [0,1]. ## @var{rp} is the allowable passband ripple measured in decibels, and @var{rs} ## is the minimum attenuation in the stop band, also in decibels. ## ## The output arguments @var{n} and @var{wc_p} (or @var{n} and @var{wc_s}) can ## be given as inputs to @code{cheby1}. ## Using @var{wc_p} makes the filter characteristic touch at least one pass band ## corner and using @var{wc_s} makes the characteristic touch at least one ## stop band corner. ## ## If @var{wp} and @var{ws} are scalars, then @var{wp} is the passband cutoff ## frequency and @var{ws} is the stopband edge frequency. If @var{ws} is ## greater than @var{wp}, the filter is a low-pass filter. If @var{wp} is ## greater than @var{ws}, the filter is a high-pass filter. ## ## If @var{wp} and @var{ws} are vectors of length 2, then @var{wp} defines the ## passband interval and @var{ws} defines the stopband interval. If @var{wp} ## is contained within @var{ws} (@var{ws1} < @var{wp1} < @var{wp2} < @var{ws2}), ## the filter is a band-pass filter. If @var{ws} is contained within @var{wp} ## (@var{wp1} < @var{ws1} < @var{ws2} < @var{wp2}), the filter is a band-stop ## or band-reject filter. ## ## If the optional argument @code{"s"} is given, the minimum order for an analog ## elliptic filter is computed. All frequencies @var{wp} and @var{ws} are ## specified in radians per second. ## @seealso{buttord, cheby1, cheb2ord, ellipord} ## @end deftypefn function [n, Wc_p, Wc_s] = cheb1ord (Wp, Ws, Rp, Rs, opt) if (nargin < 4 || nargin > 5) print_usage (); elseif (nargin == 5 && ! strcmp (opt, "s")) error ("ellipord: OPT must be the string \"s\""); endif if (nargin == 5 && strcmp (opt, "s")) s_domain = true; else s_domain = false; endif if (s_domain) validate_filter_bands ("cheb1ord", Wp, Ws, "s"); else validate_filter_bands ("cheb1ord", Wp, Ws); endif if (s_domain) # No prewarp in case of analog filter Wpw = Wp; Wsw = Ws; else ## sampling frequency of 2 Hz T = 2; Wpw = (2 / T) .* tan (pi .* Wp ./ T); # prewarp Wsw = (2 / T) .* tan (pi .* Ws ./ T); # prewarp endif ## pass/stop band to low pass filter transform: if (length (Wpw) == 2 && length (Wsw) == 2) ## Band-pass filter if (Wpw(1) > Wsw(1)) ## Modify band edges if not symmetrical. For a band-pass filter, ## the lower or upper stopband limit is moved, resulting in a smaller ## stopband than the caller requested. if (Wpw(1) * Wpw(2) < Wsw(1) * Wsw(2)) Wsw(2) = Wpw(1) * Wpw(2) / Wsw(1); else Wsw(1) = Wpw(1) * Wpw(2) / Wsw(2); endif w02 = Wpw(1) * Wpw(2); wp = Wpw(2) - Wpw(1); ws = Wsw(2) - Wsw(1); ## Band-stop / band-reject / notch filter else ## Modify band edges if not symmetrical. For a band-stop filter, ## the lower or upper passband limit is moved, resulting in a smaller ## rejection band than the caller requested. if (Wpw(1) * Wpw(2) > Wsw(1) * Wsw(2)) Wpw(2) = Wsw(1) * Wsw(2) / Wpw(1); else Wpw(1) = Wsw(1) * Wsw(2) / Wpw(2); endif w02 = Wpw(1) * Wpw(2); wp = w02 / (Wpw(2) - Wpw(1)); ws = w02 / (Wsw(2) - Wsw(1)); endif ws = ws / wp; wp = 1; ## High-pass filter elseif (Wpw > Wsw) wp = Wsw; ws = Wpw; ## Low-pass filter else wp = Wpw; ws = Wsw; endif Wa = ws ./ wp; ## compute minimum n which satisfies all band edge conditions stop_atten = 10 ^ (abs (Rs) / 10); pass_atten = 10 ^ (abs (Rp) / 10); n = ceil (acosh (sqrt ((stop_atten - 1) / (pass_atten - 1))) / acosh (Wa)); ## compute stopband frequency limits to make the the filter characteristic ## touch either at least one stop band corner or one pass band corner. epsilon = 1 / sqrt (10 ^ (.1 * abs (Rs)) - 1); k = cosh (1 / n * acosh (sqrt (1 / (10 ^ (.1 * abs (Rp)) - 1)) / epsilon)); # or k = fstop / fpass if (length (Wpw) == 2 && length (Wsw) == 2) ## Band-pass filter if (Wpw(1) > Wsw(1)) w_prime_p = Wpw; # same formula as for LP w_prime_s = Wsw / k; # " ## Band-stop / band-reject / notch filter else w_prime_p = Wpw; # same formula as for HP w_prime_s = k * Wsw; # " endif ## Applying LP to BP (respectively HP to notch) transformation to ## angular frequency to be returned: ## s_prime/wc = Q(s/w0+w0/s) or w_prime/wc = Q(w/w0-w0/w) ## Here we need to inverse above equation: ## w = abs(w_prime+-sqrt(w_prime^2+4*Q^2))/(2*Q/w0); ## freq to be returned to match pass band w0 = sqrt (prod (Wpw)); Q = w0 / diff (Wpw); # BW at -Rp dB not at -3dB wc = Wpw; W_prime = w_prime_p(1) / wc(1); # same with w_prime(2)/wc(2) wa = abs (W_prime + sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); wb = abs (W_prime - sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); Wcw_p = [wb wa]; ## freq to be returned to match stop band w0 = sqrt (prod (Wsw)); Q = w0 / diff (Wsw); # BW at -Rs dB not at -3dB wc = Wsw; W_prime = w_prime_s(1) / wc(1); # same with w_prime(2)/wc(2) wa = abs (W_prime + sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); wb = abs (W_prime - sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); Wcw_s = [wb wa]; ## High-pass filter elseif (Wpw > Wsw) Wcw_p = Wpw; # to match pass band Wcw_s = Wsw * k; # to match stop band ## Low-pass filter else Wcw_p = Wpw; # to match pass band Wcw_s = Wsw / k; # to match stop band endif if (s_domain) # No prewarp in case of analog filter Wc_p = Wcw_p; Wc_s = Wcw_s; else # Inverse frequency warping for discrete-time filter Wc_p = atan (Wcw_p .* (T / 2)) .* (T / pi); Wc_s = atan (Wcw_s .* (T / 2)) .* (T / pi); endif endfunction %!demo %! fs = 44100; %! fpass = 4000; %! fstop = 10988; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_p); %! SYS = tf (b, a, 1 / fs); %! f = (0:fs/2)'; %! W = f * (2 * pi / fs); %! [H, P] = bode (SYS, 2 * pi * f); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev low-pass Typ I : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = 4000; %! fstop = 10988; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_s); %! SYS = tf (b, a, 1 / fs); %! f = (0:fs/2)'; %! W = f * (2 * pi / fs); %! [H, P] = bode (SYS, 2 * pi * f); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev low-pass Typ I : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = 4000; %! fpass = 10988; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_p, "high"); %! f = (0:fs/2)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev high-pass Typ I : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [min(f) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = 4000; %! fpass = 10988; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_s, "high"); %! f = (0:fs/2)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev high-pass Typ I : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [min(f) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [8500, 10052]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_p); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev band-pass Typ I : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [8500, 10052]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_s); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev band-pass Typ I : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [9182 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_p); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev band-pass Typ I : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [9182 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_s); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev band-pass Typ I : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [8500, 10834]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_p, "stop"); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! Ampl = abs (H); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev notch Typ I : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [8500, 10834]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_s, "stop"); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! Ampl = abs (H); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev notch Typ I : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [9182, 12000]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_p, "stop"); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! Ampl = abs (H); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev notch Typ I : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [9182, 12000]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby1 (n, Rpass, Wn_s, "stop"); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! Ampl = abs (H); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev notch Typ I : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = 4000; %! fstop = 13584; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_p, "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev low-pass Typ I : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = 4000; %! fstop = 13584; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_s, "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev low-pass Typ I : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = 4000; %! fpass = 13584; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_p, "high", "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev high-pass Typ I : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = 4000; %! fpass = 13584; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_s, "high", "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev high-pass Typ I : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9000, 10437]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_p, "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev band-pass Typ I : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9000, 10437]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_s, "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev band-pass Typ I : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9581, 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_p, "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev band-pass Typ I : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9581, 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_s, "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev band-pass Typ I : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fstop = [9875, 10126.5823]; %! fpass = [9000, 10437]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_p, "stop", "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev notch Typ I : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = [9875, 10126.5823]; %! fpass = [9000, 10437]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_s, "stop", "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev notch Typ I : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = [9875, 10126.5823]; %! fpass = [9581 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_p, "stop", "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev notch Typ I : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = [9875, 10126.5823]; %! fpass = [9581 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb1ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby1 (n, Rpass, Wn_s, "stop", "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev notch Typ I : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!test %! # Analog band-pass %! [n, Wn_p, Wn_s] = cheb1ord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9000, 10437], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [62046, 63627]); %! assert (round (Wn_s), [61652, 64035]); %!test %! # Analog band-pass %! [n, Wn_p, Wn_s] = cheb1ord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9581 12000], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [62046, 63627]); %! assert (round (Wn_s), [61651, 64036]); %!test %! # Analog high-pass %! [n, Wn_p, Wn_s] = cheb1ord (2 * pi * 13584, 2 * pi * 4000, 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), 85351); %! assert (round (Wn_s), 56700); %!test %! # Analog low-pass %! [n, Wn_p, Wn_s] = cheb1ord (2 * pi * 4000, 2 * pi * 13584, 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), 25133); %! assert (round (Wn_s), 37832); %!test %! # Analog notch (narrow band-stop) %! [n, Wn_p, Wn_s] = cheb1ord (2 * pi * [9000, 10437], ... %! 2 * pi * [9875, 10126.5823], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [60201, 65578]); %! assert (round (Wn_s), [61074, 64640]); %!test %! # Analog notch (narrow band-stop) %! [n, Wn_p, Wn_s] = cheb1ord (2 * pi * [9581, 12000], ... %! 2 * pi * [9875, 10126.5823], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [60199, 65580]); %! assert (round (Wn_s), [61074, 64640]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb1ord (2 / fs * [9500, 9750], ... %! 2 / fs * [8500, 10052], 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9500, 9750]); %! assert (round (Wn_s), [9437, 9814]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb1ord (2 / fs * [9500, 9750], ... %! 2 / fs * [9182, 12000], 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9500, 9750]); %! assert (round (Wn_s), [9428, 9823]); %!test %! # Digital high-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb1ord (2 / fs * 10988, 2 / fs * 4000, 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), 10988); %! assert (round (Wn_s), 8197); %!test %! # Digital low-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb1ord (2 / fs * 4000, 2 / fs * 10988, 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), 4000); %! assert (round (Wn_s), 5829); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb1ord (2 / fs * [8500, 10834], ... %! 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9182, 10834]); %! assert (round (Wn_s), [9475, 10532]); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb1ord (2 / fs * [9182 12000], ... %! 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9182, 10834]); %! assert (round (Wn_s), [9475, 10532]); ## Test input validation %!error cheb1ord () %!error cheb1ord (.1) %!error cheb1ord (.1, .2) %!error cheb1ord (.1, .2, 3) %!error cheb1ord ([.1 .1], [.2 .2], 3, 4) %!error cheb1ord ([.1 .2], [.5 .6], 3, 4) %!error cheb1ord ([.1 .5], [.2 .6], 3, 4) signal-1.4.5/inst/cheb2ap.m0000644000000000000000000000360214456505401013630 0ustar0000000000000000## Copyright (C) 2013 CarnĂ« Draug ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} cheb2ap (@var{n}, @var{Rs}) ## Design lowpass analog Chebyshev type II filter. ## ## This function exists for @sc{matlab} compatibility only, and is equivalent ## to @code{cheby2 (@var{n}, @var{Rs}, 1, "s")}. ## ## Demo ## @example ## demo cheb2ap ## @end example ## ## @seealso{cheby2} ## @end deftypefn function [z, p, g] = cheb2ap (n, Rs) if (nargin != 2) print_usage(); elseif (! isscalar (n) || ! isnumeric (n) || fix (n) != n || n <= 0) error ("cheb2ap: N must be a positive integer") elseif (! isscalar (Rs) || ! isnumeric (Rs) || Rs < 0) error ("cheb2ap: RS must be a non-negative scalar") endif [z, p, g] = cheby2 (n, Rs, 1, "s"); endfunction %!error cheb2ap (-1, 3) %!error cheb2ap (3, -1) #From Steven T. Karris "Signals and Systems Second Edition" [pg. 11-36] %!demo %! w=0:0.01:1000; %! [z, p, k] = cheb2ap (3, 3); %! [b, a] = zp2tf (z, p, k); %! Gs = freqs (b, a, w); %! semilogx (w, abs (Gs)); %! xlabel('Frequency in rad/sec') %! ylabel('Magnitude of G(s)'); %! title('Type 2 Chebyshev Low-Pass Filter, k=3, 3 dB ripple in stop band') %! grid;signal-1.4.5/inst/cheb2ord.m0000644000000000000000000010703314456505401014017 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## Copyright (C) 2018 Charles Praplan ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{n} =} cheb2ord (@var{wp}, @var{ws}, @var{rp}, @var{rs}) ## @deftypefnx {Function File} {@var{n} =} cheb2ord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}) ## @deftypefnx {Function File} {@var{n} =} cheb2ord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}, "s") ## @deftypefnx {Function File} {[@var{n}, @var{wc_s}] =} cheb2ord (@dots{}) ## @deftypefnx {Function File} {[@var{n}, @var{wc_s}, @var{wc_p}] =} cheb2ord (@dots{}) ## Compute the minimum filter order of a Chebyshev type II filter with the ## desired response characteristics. The filter frequency band edges are ## specified by the passband frequency @var{wp} and stopband frequency @var{ws}. ## Frequencies are normalized to the Nyquist frequency in the range [0,1]. ## @var{rp} is the allowable passband ripple measured in decibels, and @var{rs} ## is the minimum attenuation in the stop band, also in decibels. ## ## The output arguments @var{n} and @var{wc_p} (or @var{n} and @var{wc_s}) can ## be given as inputs to @code{cheby2}. ## Using @var{wc_p} makes the filter characteristic touch at least one pass band ## corner and using @var{wc_s} makes the characteristic touch at least one ## stop band corner. ## ## If @var{wp} and @var{ws} are scalars, then @var{wp} is the passband cutoff ## frequency and @var{ws} is the stopband edge frequency. If @var{ws} is ## greater than @var{wp}, the filter is a low-pass filter. If @var{wp} is ## greater than @var{ws}, the filter is a high-pass filter. ## ## If @var{wp} and @var{ws} are vectors of length 2, then @var{wp} defines the ## passband interval and @var{ws} defines the stopband interval. If @var{wp} ## is contained within @var{ws} (@var{ws1} < @var{wp1} < @var{wp2} < @var{ws2}), ## the filter is a band-pass filter. If @var{ws} is contained within @var{wp} ## (@var{wp1} < @var{ws1} < @var{ws2} < @var{wp2}), the filter is a band-stop ## or band-reject filter. ## ## If the optional argument @code{"s"} is given, the minimum order for an analog ## elliptic filter is computed. All frequencies @var{wp} and @var{ws} are ## specified in radians per second. ## @seealso{buttord, cheb1ord, cheby2, ellipord} ## @end deftypefn function [n, Wc_p, Wc_s] = cheb2ord (Wp, Ws, Rp, Rs, opt) if (nargin < 4 || nargin > 5) print_usage (); elseif (nargin == 5 && ! strcmp (opt, "s")) error ("ellipord: OPT must be the string \"s\""); endif if (nargin == 5 && strcmp (opt, "s")) s_domain = true; else s_domain = false; endif if (s_domain) validate_filter_bands ("cheb2ord", Wp, Ws, "s"); else validate_filter_bands ("cheb2ord", Wp, Ws); endif if (s_domain) # No prewarp in case of analog filter Wpw = Wp; Wsw = Ws; else ## sampling frequency of 2 Hz T = 2; Wpw = (2 / T) .* tan (pi .* Wp ./ T); # prewarp Wsw = (2 / T) .* tan (pi .* Ws ./ T); # prewarp endif ## pass/stop band to low pass filter transform: if (length (Wpw) == 2 && length (Wsw) == 2) ## Band-pass filter if (Wpw(1) > Wsw(1)) ## Modify band edges if not symmetrical. For a band-pass filter, ## the lower or upper stopband limit is moved, resulting in a smaller ## stopband than the caller requested. if (Wpw(1) * Wpw(2) < Wsw(1) * Wsw(2)) Wsw(2) = Wpw(1) * Wpw(2) / Wsw(1); else Wsw(1) = Wpw(1) * Wpw(2) / Wsw(2); endif w02 = Wpw(1) * Wpw(2); wp = Wpw(2) - Wpw(1); ws = Wsw(2) - Wsw(1); ## Band-stop / band-reject / notch filter else ## Modify band edges if not symmetrical. For a band-stop filter, ## the lower or upper passband limit is moved, resulting in a smaller ## rejection band than the caller requested. if (Wpw(1) * Wpw(2) > Wsw(1) * Wsw(2)) Wpw(2) = Wsw(1) * Wsw(2) / Wpw(1); else Wpw(1) = Wsw(1) * Wsw(2) / Wpw(2); endif w02 = Wpw(1) * Wpw(2); wp = w02 / (Wpw(2) - Wpw(1)); ws = w02 / (Wsw(2) - Wsw(1)); endif ws = ws / wp; wp = 1; ## High-pass filter elseif (Wpw > Wsw) wp = Wsw; ws = Wpw; ## Low-pass filter else wp = Wpw; ws = Wsw; endif Wa = ws ./ wp; ## compute minimum n which satisfies all band edge conditions stop_atten = 10 ^ (abs (Rs) / 10); pass_atten = 10 ^ (abs (Rp) / 10); n = ceil (acosh (sqrt ((stop_atten - 1) / (pass_atten - 1))) / acosh (Wa)); ## compute stopband frequency limits to make the the filter characteristic ## touch either at least one stop band corner or one pass band corner. epsilon = 1 / sqrt (10 ^ (.1 * abs (Rs)) - 1); k = cosh (1 / n * acosh (sqrt (1 / (10 ^ (.1 * abs (Rp)) - 1)) / epsilon)); # or k = fstop / fpass if (length (Wpw) == 2 && length (Wsw) == 2) ## Band-pass filter if (Wpw(1) > Wsw(1)) w_prime_s = Wsw; # same formula as for LP w_prime_p = k * Wpw; # " ## Band-stop / band-reject / notch filter else w_prime_s = Wsw; # same formula as for HP w_prime_p = Wpw / k; # " endif ## Applying LP to BP (respectively HP to notch) transformation to ## angular frequency to be returned: ## s_prime/wc = Q(s/w0+w0/s) or w_prime/wc = Q(w/w0-w0/w) ## Here we need to inverse above equation: ## w = abs(w_prime+-sqrt(w_prime^2+4*Q^2))/(2*Q/w0); ## freq to be returned to match pass band w0 = sqrt (prod (Wpw)); Q = w0 / diff (Wpw); # BW at -Rp dB not at -3dB wc = Wpw; W_prime = w_prime_p(1) / wc(1); # same with w_prime(2)/wc(2) wa = abs (W_prime + sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); wb = abs (W_prime - sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); Wcw_p = [wb wa]; ## freq to be returned to match stop band w0 = sqrt (prod (Wsw)); Q = w0 / diff (Wsw); # BW at -Rs dB not at -3dB wc = Wsw; W_prime = w_prime_s(1) / wc(1); # same with w_prime(2)/wc(2) wa = abs (W_prime + sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); wb = abs (W_prime - sqrt (W_prime ^ 2 + 4 * Q ^ 2)) / (2 * Q / w0); Wcw_s = [wb wa]; ## High-pass filter elseif (Wpw > Wsw) Wcw_s = Wsw; # to match stop band Wcw_p = Wpw / k; # to match pass band ## Low-pass filter else Wcw_s = Wsw; # to match stop band Wcw_p = k * Wpw; # to match pass band endif if (s_domain) # No prewarp in case of analog filter Wc_s = Wcw_s; Wc_p = Wcw_p; else # Inverse frequency warping for discrete-time filter Wc_s = atan (Wcw_s .* (T / 2)) .* (T / pi); Wc_p = atan (Wcw_p .* (T / 2)) .* (T / pi); endif endfunction %!demo %! fs = 44100; %! fpass = 4000; %! fstop = 10988; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_p); %! SYS = tf (b, a, 1 / fs); %! f = (0:fs/2)'; %! W = f * (2 * pi / fs); %! [H, P] = bode (SYS, 2 * pi * f); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev low-pass Typ II : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = 4000; %! fstop = 10988; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_s); %! SYS = tf (b, a, 1 / fs); %! f = (0:fs/2)'; %! W = f * (2 * pi / fs); %! [H, P] = bode (SYS, 2 * pi * f); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev low-pass Typ II : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = 4000; %! fpass = 10988; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_p, "high"); %! f = (0:fs/2)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev high-pass Typ II : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [min(f) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = 4000; %! fpass = 10988; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_s, "high"); %! f = (0:fs/2)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev high-pass Typ II : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [min(f) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [8500, 10052]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_p); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev band-pass Typ II : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [8500, 10052]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_s); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev band-pass Typ II : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [9182 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_p); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev band-pass Typ II : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fpass = [9500 9750]; %! fstop = [9182 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_s); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev band-pass Typ II : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [8500, 10834]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_p, "stop"); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! Ampl = abs (H); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev notch Typ II : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [8500, 10834]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_s, "stop"); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! Ampl = abs (H); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev notch Typ II : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [9182, 12000]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_p, "stop"); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! Ampl = abs (H); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev notch Typ II : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fs = 44100; %! fstop = [9875, 10126.5823]; %! fpass = [9182, 12000]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2 / fs * fpass; %! Wstop = 2 / fs * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = cheby2 (n, Rstop, Wn_s, "stop"); %! f = (6000:14000)'; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! Ampl = abs (H); %! plot (f, 20 * log10 (abs (H))); %! title ("Digital Chebyshev notch Typ II : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on; %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = 4000; %! fstop = 13584; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_p, "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev low-pass Typ II : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = 4000; %! fstop = 13584; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_s, "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev low-pass Typ II : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on; %! plot (outline_lp_pass_x, outline_lp_pass_y, "m"); %! plot (outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = 4000; %! fpass = 13584; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_p, "high", "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev high-pass Typ II : matching pass band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = 4000; %! fpass = 13584; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_s, "high", "s"); %! f = 1000:10:100000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev high-pass Typ II : matching stop band"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on; %! plot (outline_hp_pass_x, outline_hp_pass_y, "m"); %! plot (outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9000, 10437]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_p, "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev band-pass Typ II : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9000, 10437]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_s, "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev band-pass Typ II : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9581, 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_p, "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev band-pass Typ II : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fpass = [9875, 10126.5823]; %! fstop = [9581, 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_s, "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev band-pass Typ II : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , ... %! -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m"); %! plot (outline_bp_stop_x, outline_bp_stop_y, "m"); %! grid on; %! ylim ([-80, 0]); %!demo %! fstop = [9875, 10126.5823]; %! fpass = [9000, 10437]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_p, "stop", "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev notch Typ II : matching pass band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = [9875, 10126.5823]; %! fpass = [9000, 10437]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_s, "stop", "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev notch Typ II : matching stop band, limit on upper freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = [9875, 10126.5823]; %! fpass = [9581 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_p, "stop", "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev notch Typ II : matching pass band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!demo %! fstop = [9875, 10126.5823]; %! fpass = [9581 12000]; %! Rpass = 1; %! Rstop = 26; %! Wpass = 2 * pi * fpass; %! Wstop = 2 * pi * fstop; %! [n, Wn_p, Wn_s] = cheb2ord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = cheby2 (n, Rstop, Wn_s, "stop", "s"); %! f = 6000:14000; %! W = 2 * pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! title ("Analog Chebyshev notch Typ II : matching stop band, limit on lower freq"); %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! grid on; %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), ... %! fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0, 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m"); %! plot (outline_notch_pass_x_b, outline_notch_pass_y_b, "m"); %! plot (outline_notch_stop_x, outline_notch_stop_y, "m"); %! ylim ([-80, 0]); %!test %! # Analog band-pass %! [n, Wn_p, Wn_s] = cheb2ord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9000, 10437], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [61074, 64640]); %! assert (round (Wn_s), [60201, 65578]); %!test %! # Analog band-pass %! [n, Wn_p, Wn_s] = cheb2ord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9581 12000], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [61074, 64640]); %! assert (round (Wn_s), [60199, 65580]); %!test %! # Analog high-pass %! [n, Wn_p, Wn_s] = cheb2ord (2 * pi * 13584, 2 * pi * 4000, 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), 37832); %! assert (round (Wn_s), 25133); %!test %! # Analog low-pass %! [n, Wn_p, Wn_s] = cheb2ord (2 * pi * 4000, 2 * pi * 13584, 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), 56700); %! assert (round (Wn_s), 85351); %!test %! # Analog notch (narrow band-stop) %! [n, Wn_p, Wn_s] = cheb2ord (2 * pi * [9000, 10437], ... %! 2 * pi * [9875, 10126.5823], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [61652, 64035]); %! assert (round (Wn_s), [62046, 63627]); %!test %! # Analog notch (narrow band-stop) %! [n, Wn_p, Wn_s] = cheb2ord (2 * pi * [9581, 12000], ... %! 2 * pi * [9875, 10126.5823], 1, 26, "s"); %! assert (n, 3); %! assert (round (Wn_p), [61651, 64036]); %! assert (round (Wn_s), [62046, 63627]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb2ord (2 / fs * [9500, 9750], ... %! 2 / fs * [8500, 10052], 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9344, 9908]); %! assert (round (Wn_s), [9203, 10052]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb2ord (2 / fs * [9500, 9750], ... %! 2 / fs * [9182, 12000], 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9344, 9908]); %! assert (round (Wn_s), [9182, 10073]); %!test %! # Digital high-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb2ord (2 / fs * 10988, 2 / fs * 4000, 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), 5829); %! assert (round (Wn_s), 4000); %!test %! # Digital low-pass %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb2ord (2 / fs * 4000, 2 / fs * 10988, 1, 26); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), 8197); %! assert (round (Wn_s), 10988); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb2ord (2 / fs * [8500, 10834], ... %! 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9804, 10198]); %! assert (round (Wn_s), [9875, 10127]); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn_p, Wn_s] = cheb2ord (2 / fs * [9182 12000], ... %! 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn_p = Wn_p * fs / 2; %! Wn_s = Wn_s * fs / 2; %! assert (n, 3); %! assert (round (Wn_p), [9804, 10198]); %! assert (round (Wn_s), [9875, 10127]); ## Test input validation %!error cheb2ord () %!error cheb2ord (.1) %!error cheb2ord (.1, .2) %!error cheb2ord (.1, .2, 3) %!error cheb2ord ([.1 .1], [.2 .2], 3, 4) %!error cheb2ord ([.1 .2], [.5 .6], 3, 4) %!error cheb2ord ([.1 .5], [.2 .6], 3, 4) signal-1.4.5/inst/chebwin.m0000644000000000000000000000640314456505401013745 0ustar0000000000000000## Copyright (C) 2002 AndrĂ© Carezia ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} chebwin (@var{m}) ## @deftypefnx {Function File} {} chebwin (@var{m}, @var{at}) ## ## Return the filter coefficients of a Dolph-Chebyshev window of length @var{m}. ## The Fourier transform of the window has a stop-band attenuation of @var{at} ## dB. The default attenuation value is 100 dB. ## ## For the definition of the Chebyshev window, see ## ## * Peter Lynch, "The Dolph-Chebyshev Window: A Simple Optimal Filter", ## Monthly Weather Review, Vol. 125, pp. 655-660, April 1997. ## (http://www.maths.tcd.ie/~plynch/Publications/Dolph.pdf) ## ## * C. Dolph, "A current distribution for broadside arrays which ## optimizes the relationship between beam width and side-lobe level", ## Proc. IEEE, 34, pp. 335-348. ## ## The window is described in frequency domain by the expression: ## ## @example ## @group ## Cheb(m-1, beta * cos(pi * k/m)) ## W(k) = ------------------------------- ## Cheb(m-1, beta) ## @end group ## @end example ## ## with ## ## @example ## @group ## beta = cosh(1/(m-1) * acosh(10^(at/20)) ## @end group ## @end example ## ## and Cheb(m,x) denoting the m-th order Chebyshev polynomial calculated ## at the point x. ## ## Note that the denominator in W(k) above is not computed, and after ## the inverse Fourier transform the window is scaled by making its ## maximum value unitary. ## ## @seealso{kaiser} ## @end deftypefn function w = chebwin (m, at) if (nargin < 1 || nargin > 2) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("chebwin: M must be a positive integer"); elseif (nargin == 1) at = 100; elseif (! (isscalar (at) && isreal (at))) error ("chebwin: AT must be a real scalar"); endif if (m == 1) w = 1; else ## beta calculation gamma = 10^(-at/20); beta = cosh(1/(m-1) * acosh(1/gamma)); ## freq. scale k = (0:m-1); x = beta*cos(pi*k/m); ## Chebyshev window (freq. domain) p = cheb(m-1, x); ## inverse Fourier transform if (rem(m,2)) w = real(fft(p)); M = (m+1)/2; w = w(1:M)/w(1); w = [w(M:-1:2) w]'; else ## half-sample delay (even order) p = p.*exp(j*pi/m * (0:m-1)); w = real(fft(p)); M = m/2+1; w = w/w(2); w = [w(M:-1:2) w(2:M)]'; endif endif w = w ./ max (w (:)); endfunction %!assert (chebwin (1), 1) %!assert (chebwin (2), ones (2, 1)) %% Test input validation %!error chebwin () %!error chebwin (0.5) %!error chebwin (-1) %!error chebwin (ones (1, 4)) %!error chebwin (1, 2, 3) signal-1.4.5/inst/cheby1.m0000644000000000000000000001274014456505401013502 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## Copyright (C) 2003 Doug Stewart ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{b}, @var{a}] =} cheby1 (@var{n}, @var{rp}, @var{w}) ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby1 (@var{n}, @var{rp}, @var{w}, "high") ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby1 (@var{n}, @var{rp}, [@var{wl}, @var{wh}]) ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby1 (@var{n}, @var{rp}, [@var{wl}, @var{wh}], "stop") ## @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} cheby1 (@dots{}) ## @deftypefnx {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} cheby1 (@dots{}) ## @deftypefnx {Function File} {[@dots{}] =} cheby1 (@dots{}, "s") ## Generate a Chebyshev type I filter with @var{rp} dB of passband ripple. ## ## [b, a] = cheby1(n, Rp, Wc) ## low pass filter with cutoff pi*Wc radians ## ## [b, a] = cheby1(n, Rp, Wc, 'high') ## high pass filter with cutoff pi*Wc radians ## ## [b, a] = cheby1(n, Rp, [Wl, Wh]) ## band pass filter with edges pi*Wl and pi*Wh radians ## ## [b, a] = cheby1(n, Rp, [Wl, Wh], 'stop') ## band reject filter with edges pi*Wl and pi*Wh radians ## ## [z, p, g] = cheby1(...) ## return filter as zero-pole-gain rather than coefficients of the ## numerator and denominator polynomials. ## ## [...] = cheby1(...,'s') ## return a Laplace space filter, W can be larger than 1. ## ## [a,b,c,d] = cheby1(...) ## return state-space matrices ## ## References: ## ## Parks & Burrus (1987). Digital Filter Design. New York: ## John Wiley & Sons, Inc. ## @end deftypefn function [a, b, c, d] = cheby1 (n, rp, w, varargin) if (nargin > 5 || nargin < 3 || nargout > 4) print_usage (); endif ## interpret the input parameters if (! (isscalar (n) && (n == fix (n)) && (n > 0))) error ("cheby1: filter order N must be a positive integer"); endif stop = false; digital = true; for i = 1:numel (varargin) switch (varargin{i}) case "s" digital = false; case "z" digital = true; case {"high", "stop"} stop = true; case {"low", "pass"} stop = false; otherwise error ("cheby1: expected [high|stop] or [s|z]"); endswitch endfor if (! ((numel (w) <= 2) && (rows (w) == 1 || columns (w) == 1))) error ("cheby1: frequency must be given as WC or [WL, WH]"); elseif ((numel (w) == 2) && (w(2) <= w(1))) error ("cheby1: W(1) must be less than W(2)"); endif if (digital && ! all ((w >= 0) & (w <= 1))) error ("cheby1: all elements of W must be in the range [0,1]"); elseif (! digital && ! all (w >= 0)) error ("cheby1: all elements of W must be in the range [0,inf]"); endif if (! (isscalar (rp) && isnumeric (rp) && (rp >= 0))) error ("cheby1: passband ripple RP must be a non-negative scalar"); endif ## Prewarp to the band edges to s plane if (digital) T = 2; # sampling frequency of 2 Hz w = 2 / T * tan (pi * w / T); endif ## Generate splane poles and zeros for the Chebyshev type 1 filter C = 1; ## default cutoff frequency epsilon = sqrt (10^(rp / 10) - 1); v0 = asinh (1 / epsilon) / n; pole = exp (1i * pi * [-(n - 1):2:(n - 1)] / (2 * n)); pole = -sinh (v0) * real (pole) + 1i * cosh (v0) * imag (pole); zero = []; ## compensate for amplitude at s=0 gain = prod (-pole); ## if n is even, the ripple starts low, but if n is odd the ripple ## starts high. We must adjust the s=0 amplitude to compensate. if (rem (n, 2) == 0) gain = gain / 10^(rp / 20); endif ## splane frequency transform [zero, pole, gain] = sftrans (zero, pole, gain, w, stop); ## Use bilinear transform to convert poles to the z plane if (digital) [zero, pole, gain] = bilinear (zero, pole, gain, T); endif ## convert to the correct output form ## note that poly always outputs a row vector if (nargout <= 2) a = real (gain * poly (zero)); b = real (poly (pole)); elseif (nargout == 3) a = zero(:); b = pole(:); c = gain; else ## output ss results [a, b, c, d] = zp2ss (zero, pole, gain); endif endfunction %% Test input validation %!error [a, b] = cheby1 () %!error [a, b] = cheby1 (1) %!error [a, b] = cheby1 (1, 2) %!error [a, b] = cheby1 (1, 2, 3, 4, 5, 6) %!error [a, b] = cheby1 (.5, 2, .2) %!error [a, b] = cheby1 (3, 2, .2, "invalid") %% Test output orientation %!test %! cheby1 (3, 4, .5); %! assert (isrow (ans)); %!test %! A = cheby1 (3, 4, .5); %! assert (isrow (A)); %!test %! [A, B] = cheby1 (3, 4, .5); %! assert (isrow (A)); %! assert (isrow (B)); %!test %! [z, p, g] = cheby1 (3, 4, .5); %! assert (iscolumn (z)); %! assert (iscolumn (p)); %! assert (isscalar (g)); %!test %! [a, b, c, d] = cheby1 (3, 4, .5); %! assert (ismatrix (a)); %! assert (iscolumn (b)); %! assert (isrow (c)); %! assert (isscalar (d)); signal-1.4.5/inst/cheby2.m0000644000000000000000000001362714456505401013510 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## Copyright (C) 2003 Doug Stewart ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{b}, @var{a}] =} cheby2 (@var{n}, @var{rs}, @var{wc}) ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby2 (@var{n}, @var{rs}, @var{wc}, "high") ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby2 (@var{n}, @var{rs}, [@var{wl}, @var{wh}]) ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} cheby2 (@var{n}, @var{rs}, [@var{wl}, @var{wh}], "stop") ## @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} cheby2 (@dots{}) ## @deftypefnx {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} cheby2 (@dots{}) ## @deftypefnx {Function File} {[@dots{}] =} cheby2 (@dots{}, "s") ## Generate a Chebyshev type II filter with @var{rs} dB of stopband attenuation. ## ## [b, a] = cheby2(n, Rs, Wc) ## low pass filter with cutoff pi*Wc radians ## ## [b, a] = cheby2(n, Rs, Wc, 'high') ## high pass filter with cutoff pi*Wc radians ## ## [b, a] = cheby2(n, Rs, [Wl, Wh]) ## band pass filter with edges pi*Wl and pi*Wh radians ## ## [b, a] = cheby2(n, Rs, [Wl, Wh], 'stop') ## band reject filter with edges pi*Wl and pi*Wh radians ## ## [z, p, g] = cheby2(...) ## return filter as zero-pole-gain rather than coefficients of the ## numerator and denominator polynomials. ## ## [...] = cheby2(...,'s') ## return a Laplace space filter, W can be larger than 1. ## ## [a,b,c,d] = cheby2(...) ## return state-space matrices ## ## References: ## ## Parks & Burrus (1987). Digital Filter Design. New York: ## John Wiley & Sons, Inc. ## @end deftypefn function [a, b, c, d] = cheby2 (n, rs, w, varargin) if (nargin > 5 || nargin < 3 || nargout > 4) print_usage (); endif ## interpret the input parameters if (! (isscalar (n) && (n == fix (n)) && (n > 0))) error ("cheby2: filter order N must be a positive integer"); endif stop = false; digital = true; for i = 1:numel (varargin) switch (varargin{i}) case "s" digital = false; case "z" digital = true; case {"high", "stop"} stop = true; case {"low", "pass"} stop = false; otherwise error ("cheby2: expected [high|stop] or [s|z]"); endswitch endfor if (! ((numel (w) <= 2) && (rows (w) == 1 || columns (w) == 1))) error ("cheby2: frequency must be given as WC or [WL, WH]"); elseif ((numel (w) == 2) && (w(2) <= w(1))) error ("cheby2: W(1) must be less than W(2)"); endif if (digital && ! all ((w >= 0) & (w <= 1))) error ("cheby2: all elements of W must be in the range [0,1]"); elseif (! digital && ! all (w >= 0)) error ("cheby2: all elements of W must be in the range [0,inf]"); endif if (! (isscalar (rs) && isnumeric (rs) && (rs >= 0))) error ("cheby2: stopband attenuation RS must be a non-negative scalar"); endif ## Prewarp to the band edges to s plane if (digital) T = 2; # sampling frequency of 2 Hz w = 2 / T * tan (pi * w / T); endif ## Generate splane poles and zeros for the Chebyshev type 2 filter ## From: Stearns, SD; David, RA; (1988). Signal Processing Algorithms. ## New Jersey: Prentice-Hall. C = 1; ## default cutoff frequency lambda = 10^(rs / 20); phi = log (lambda + sqrt (lambda^2 - 1)) / n; theta = pi * ([1:n] - 0.5) / n; alpha = -sinh (phi) * sin (theta); beta = cosh (phi) * cos (theta); if (rem (n, 2)) ## drop theta==pi/2 since it results in a zero at infinity zero = 1i * C ./ cos (theta([1:(n - 1) / 2, (n + 3) / 2:n])); else zero = 1i * C ./ cos (theta); endif pole = C ./ (alpha.^2 + beta.^2) .* (alpha - 1i * beta); ## Compensate for amplitude at s=0 ## Because of the vagaries of floating point computations, the ## prod(pole)/prod(zero) sometimes comes out as negative and ## with a small imaginary component even though analytically ## the gain will always be positive, hence the abs(real(...)) gain = abs (real (prod (pole) / prod (zero))); ## splane frequency transform [zero, pole, gain] = sftrans (zero, pole, gain, w, stop); ## Use bilinear transform to convert poles to the z plane if (digital) [zero, pole, gain] = bilinear (zero, pole, gain, T); endif ## convert to the correct output form ## note that poly always outputs a row vector if (nargout <= 2) a = real (gain * poly (zero)); b = real (poly (pole)); elseif (nargout == 3) a = zero(:); b = pole(:); c = gain; else ## output ss results [a, b, c, d] = zp2ss (zero, pole, gain); endif endfunction %% Test input validation %!error [a, b] = cheby2 () %!error [a, b] = cheby2 (1) %!error [a, b] = cheby2 (1, 2) %!error [a, b] = cheby2 (1, 2, 3, 4, 5, 6) %!error [a, b] = cheby2 (.5, 40, .2) %!error [a, b] = cheby2 (3, 40, .2, "invalid") % %% Test output orientation %!test %! cheby2 (3, 4, .5); %! assert (isrow (ans)); %!test %! A = cheby2 (3, 4, .5); %! assert (isrow (A)); %!test %! [A, B] = cheby2 (3, 4, .5); %! assert (isrow (A)); %! assert (isrow (B)); %!test %! [z, p, g] = cheby2 (3, 4, .5); %! assert (iscolumn (z)); %! assert (iscolumn (p)); %! assert (isscalar (g)); %!test %! [a, b, c, d] = cheby2 (3, 4, .5); %! assert (ismatrix (a)); %! assert (iscolumn (b)); %! assert (isrow (c)); %! assert (isscalar (d)); signal-1.4.5/inst/chirp.m0000644000000000000000000001233714456505401013436 0ustar0000000000000000## Copyright (C) 1999-2000 Paul Kienzle ## Copyright (C) 2018-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} chirp (@var{t}) ## @deftypefnx {Function File} {} chirp (@var{t}, @var{f0}) ## @deftypefnx {Function File} {} chirp (@var{t}, @var{f0}, @var{t1}) ## @deftypefnx {Function File} {} chirp (@var{t}, @var{f0}, @var{t1}, @var{f1}) ## @deftypefnx {Function File} {} chirp (@var{t}, @var{f0}, @var{t1}, @var{f1}, @var{shape}) ## @deftypefnx {Function File} {} chirp (@var{t}, @var{f0}, @var{t1}, @var{f1}, @var{shape}, @var{phase}) ## ## Evaluate a chirp signal at time @var{t}. A chirp signal is a frequency ## swept cosine wave. ## ## @table @var ## @item t ## vector of times to evaluate the chirp signal ## @item f0 ## frequency at time t=0 [ 0 Hz ] ## @item t1 ## time t1 [ 1 sec ] ## @item f1 ## frequency at time t=t1 [ 100 Hz ] ## @item shape ## shape of frequency sweep ## 'linear' f(t) = (f1-f0)*(t/t1) + f0 ## 'quadratic' f(t) = (f1-f0)*(t/t1)^2 + f0 ## 'logarithmic' f(t) = (f1/f0)^(t/t1) * f0 ## @item phase ## phase shift at t=0 ## @end table ## ## For example: ## ## @example ## @group ## @c doctest: +SKIP ## specgram (chirp ([0:0.001:5])); # default linear chirp of 0-100Hz in 1 sec ## specgram (chirp ([-2:0.001:15], 400, 10, 100, "quadratic")); ## soundsc (chirp ([0:1/8000:5], 200, 2, 500, "logarithmic"), 8000); ## @end group ## @end example ## ## If you want a different sweep shape f(t), use the following: ## ## @group ## @verbatim ## y = cos (2 * pi * integral (f(t)) + phase); ## @end verbatim ## @end group ## @end deftypefn function y = chirp (t, f0, t1, f1, shape, phase) if (nargin < 1 || nargin > 6) print_usage (); endif if ((nargin < 2) || (isempty (f0))) ## The default value for f0 depends on the shape if ((nargin >= 5) && (ischar (shape)) && (numel (shape) >= 2) ... && (strncmpi (shape, "logarithmic", numel (shape)))) f0 = 1e-6; else f0 = 0; endif endif if ((nargin < 3) || (isempty (t1))) t1 = 1; endif if ((nargin < 4) || (isempty (f1))) f1 = 100; endif if ((nargin < 5) || (isempty (shape))) shape = "linear"; endif if ((nargin < 6) || (isempty (phase))) phase = 0; endif phase = 2 * pi * phase / 360; if ((numel (shape) >= 2) && (strncmpi (shape, "linear", numel (shape)))) a = pi * (f1 - f0) / t1; b = 2 * pi * f0; y = cos (a * t.^2 + b * t + phase); elseif ((numel (shape) >= 1) ... && (strncmpi (shape, "quadratic", numel (shape)))) a = (2/3 * pi * (f1 - f0) / t1 / t1); b = 2 * pi * f0; y = cos (a * t.^3 + b * t + phase); elseif ((numel (shape) >= 2) ... && (strncmpi (shape, "logarithmic", numel (shape)))) a = 2 * pi * f0 * t1 / log (f1 / f0); x = (f1 / f0) .^ (1 / t1); y = cos (a * x.^t + phase); else error ("chirp: invalid frequency sweep shape '%s'", shape); endif endfunction %!demo %! t = 0:0.001:5; %! y = chirp (t); %! specgram (y, 256, 1000); %! %------------------------------------------------------------ %! % Shows linear sweep of 100 Hz/sec starting at zero for 5 sec %! % since the sample rate is 1000 Hz, this should be a diagonal %! % from bottom left to top right. %!demo %! t = -2:0.001:15; %! y = chirp (t, 400, 10, 100, "quadratic"); %! [S, f, t] = specgram (y, 256, 1000); %! t = t - 2; %! imagesc(t, f, 20 * log10 (abs (S))); %! set (gca (), "ydir", "normal"); %! xlabel ("Time"); %! ylabel ("Frequency"); %! %------------------------------------------------------------ %! % Shows a quadratic chirp of 400 Hz at t=0 and 100 Hz at t=10 %! % Time goes from -2 to 15 seconds. %!demo %! t = 0:1/8000:5; %! y = chirp (t, 200, 2, 500, "logarithmic"); %! specgram (y, 256, 8000); %! %------------------------------------------------------------- %! % Shows a logarithmic chirp of 200 Hz at t=0 and 500 Hz at t=2 %! % Time goes from 0 to 5 seconds at 8000 Hz. ## Test shape defaults and abbreviations %!shared t %! t = (0:5000) ./ 1000; %!test %! y1 = chirp (t); %! y2 = chirp (t, 0, 1, 100, "linear", 0); %! assert (y2, y1) %!test %! y1 = chirp (t, [], [], [], "li"); %! y2 = chirp (t, 0, 1, 100, "linear", 0); %! assert (y2, y1) %!test %! y1 = chirp (t, [], [], [], "q"); %! y2 = chirp (t, 0, 1, 100, "quadratic", 0); %! assert (y2, y1) %!test %! y1 = chirp (t, [], [], [], "lo"); %! y2 = chirp (t, 1e-6, 1, 100, "logarithmic", 0); %! assert (y2, y1) ## Test input validation %!error chirp () %!error chirp (1, 2, 3, 4, 5, 6, 7) %!error chirp (0, [], [], [], "l") %!error chirp (0, [], [], [], "foo") signal-1.4.5/inst/clustersegment.m0000644000000000000000000000513314456505401015371 0ustar0000000000000000## Copyright (C) 2021 Juan Pablo Carbajal ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{clusteridx} =} clustersegment (@var{unos}) ## Calculate boundary indexes of clusters of 1's. ## ## The function calculates the initial index and end index of the sequences of ## 1's in the rows of @var{unos}. The clusters are sought in the rows of the ## array @var{unos}. ## ## The result is returned in a cell array of size 1-by-@var{Np}, where @var{Np} ## is the number of rows in @var{unos}. Each element of the cell has two rows. ## The first row is the initial index of a sequence of 1's and the second row ## is the end index of that sequence. ## ## If @var{Np} == 1 the output is a matrix with two rows. ## ## The function works by finding the indexes of jumps between consecutive ## values in the rows of @var{unos}. ## ## @end deftypefn function contRange = clustersegment(xhi) ## Find discontinuities bool_discon = diff (xhi, 1, 2); [Np Na] = size (xhi); contRange = cell (1, Np); for i = 1:Np idxUp = find (bool_discon(i,:) > 0) + 1; idxDwn = find (bool_discon(i,:) < 0); tLen = length (idxUp) + length (idxDwn); if xhi(i,1) == 1 ## first event was down contRange{i}(1) = 1; contRange{i}(2:2:tLen+1) = idxDwn; contRange{i}(3:2:tLen+1) = idxUp; else ## first event was up contRange{i}(1:2:tLen) = idxUp; contRange{i}(2:2:tLen) = idxDwn; endif if xhi(i,end) == 1 ## last event was up contRange{i}(end+1) = Na; endif tLen = length (contRange{i}); if tLen ~= 0 contRange{i} = reshape (contRange{i}, 2, tLen / 2); endif endfor if Np == 1 contRange = cell2mat (contRange); endif endfunction %!demo %! xhi = [0 0 1 1 1 0 0 1 0 0 0 1 1]; %! ranges = clustersegment (xhi) %! %! % The first sequence of 1's in xhi lies in the interval %! ranges(1,1):ranges(2,1) %!demo %! xhi = rand(3,10)>0.4 %! ranges = clustersegment(xhi) signal-1.4.5/inst/cmorwavf.m0000644000000000000000000000227014456505401014150 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{psi}, @var{x}] =} cmorwavf (@var{lb}, @var{ub}, @var{n}, @var{fb}, @var{fc}) ## Compute the Complex Morlet wavelet. ## @end deftypefn function [psi,x] = cmorwavf (lb,ub,n,fb,fc) if (nargin ~= 5) print_usage; elseif (n <= 0 || floor(n) ~= n) error("n must be an integer strictly positive"); endif x = linspace(lb,ub,n); psi =((pi*fb)^(-0.5))*exp(2*i*pi*fc.*x).*exp(-x.^2/fb); endfunction signal-1.4.5/inst/cohere.m0000644000000000000000000000410414456505401013567 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{Pxx}, @var{freq}]} = cohere(@var{x},@var{y},@var{Nfft},@var{Fs},@var{window},@var{overlap},@var{range},@var{plot_type},@var{detrend}) ## Estimate (mean square) coherence of signals "x" and "y". ## ## Use the Welch (1967) periodogram/FFT method. ## ## Compatible with Matlab R11 cohere and earlier. ## ## See "help pwelch" for description of arguments, hints and references ## --- especially hint (7) for Matlab R11 defaults. ## @end deftypefn function varargout = cohere(varargin) ## if ( nargin<2 ) error( 'cohere: Need at least 2 args. Use help cohere.' ); endif nvarargin = length(varargin); ## remove any pwelch RESULT args and add 'trans' for iarg=1:nvarargin arg = varargin{iarg}; if ( ~isempty(arg) && ischar(arg) && ( strcmp(arg,'power') || ... strcmp(arg,'cross') || strcmp(arg,'trans') || ... strcmp(arg,'coher') || strcmp(arg,'ypower') )) varargin{iarg} = []; endif endfor varargin{nvarargin+1} = 'coher'; ## saved_compatib = pwelch('R11-'); if ( nargout==0 ) pwelch(varargin{:}); elseif ( nargout==1 ) Pxx = pwelch(varargin{:}); varargout{1} = Pxx; elseif ( nargout>=2 ) [Pxx,f] = pwelch(varargin{:}); varargout{1} = Pxx; varargout{2} = f; endif pwelch(saved_compatib); saved_compatib = 0; endfunction signal-1.4.5/inst/convmtx.m0000644000000000000000000000345614456505401014031 0ustar0000000000000000## Copyright (C) 2003 David Bateman ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} convmtx (@var{a}, @var{n}) ## If @var{a} is a column vector and @var{x} is a column vector ## of length @var{n}, then ## ## @code{convmtx(@var{a}, @var{n}) * @var{x}} ## ## gives the convolution of of @var{a} and @var{x} and is the ## same as @code{conv(@var{a}, @var{x})}. The difference is if ## many vectors are to be convolved with the same vector, then ## this technique is possibly faster. ## ## Similarly, if @var{a} is a row vector and @var{x} is a row ## vector of length @var{n}, then ## ## @code{@var{x} * convmtx(@var{a}, @var{n})} ## ## is the same as @code{conv(@var{x}, @var{a})}. ## @end deftypefn ## @seealso{conv} function b = convmtx (a, n) if (nargin != 2) print_usage; endif [r, c] = size(a); if ((r != 1) && (c != 1)) || (r*c == 0) error("convmtx: expecting vector argument"); endif b = toeplitz([a(:); zeros(n-1,1)],[a(1); zeros(n-1,1)]); if (c > r) b = b.'; endif endfunction %!assert(convmtx([3,4,5],3),[3,4,5,0,0;0,3,4,5,0;0,0,3,4,5]) %!assert(convmtx([3;4;5],3),[3,0,0;4,3,0;5,4,3;0,5,4;0,0,5]) signal-1.4.5/inst/cplxreal.m0000644000000000000000000000725014456505401014141 0ustar0000000000000000## Copyright (C) 2005 Julius O. Smith III ## Copyright (C) 2018-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{zc}, @var{zr}] =} cplxreal (@var{z}) ## @deftypefnx {Function File} {[@var{zc}, @var{zr}] =} cplxreal (@var{z}, @var{tol}) ## @deftypefnx {Function File} {[@var{zc}, @var{zr}] =} cplxreal (@var{z}, @var{tol}, @var{dim}) ## Sort the numbers @var{z} into complex-conjugate-valued and real-valued ## elements. The positive imaginary complex numbers of each complex conjugate ## pair are returned in @var{zc} and the real numbers are returned in @var{zr}. ## ## @var{tol} is a weighting factor in the range [0, 1) which determines the ## tolerance of the matching. The default value is @code{100 * eps} and the ## resulting tolerance for a given complex pair is ## @code{@var{tol} * abs (@var{z}(i)))}. ## ## By default the complex pairs are sorted along the first non-singleton ## dimension of @var{z}. If @var{dim} is specified, then the complex pairs are ## sorted along this dimension. ## ## Signal an error if some complex numbers could not be paired. Signal an ## error if all complex numbers are not exact conjugates (to within @var{tol}). ## Note that there is no defined order for pairs with identical real parts but ## differing imaginary parts. ## @seealso{cplxpair} ## @end deftypefn function [zc, zr] = cplxreal (z, tol, dim) if (nargin < 1 || nargin > 3) print_usage (); endif if (isempty (z)) zc = zeros (size (z)); zr = zeros (size (z)); return; endif cls = ifelse (isa (z, "single"), "single", "double"); if (nargin < 2 || isempty (tol)) tol = 100 * eps (cls); endif args = cell (1, nargin); args{1} = z; args{2} = tol; if (nargin >= 3) args{3} = dim; endif zcp = cplxpair (args{:}); nz = length (z); idx = nz; while ((idx > 0) && (zcp(idx) == 0 || (abs (imag (zcp(idx))) ./ abs (zcp(idx))) <= tol)) zcp(idx) = real (zcp(idx)); idx--; endwhile if (mod (idx, 2) != 0) error ("cplxreal: odd number of complex values was returned from cplxpair"); endif zc = zcp(2:2:idx); zr = zcp(idx+1:nz); endfunction %!test %! [zc, zr] = cplxreal ([]); %! assert (isempty (zc)) %! assert (isempty (zr)) %!test %! [zc, zr] = cplxreal (1); %! assert (isempty (zc)) %! assert (zr, 1) %!test %! [zc, zr] = cplxreal ([1+1i, 1-1i]); %! assert (zc, 1+1i) %! assert (isempty (zr)) %!test %! [zc, zr] = cplxreal (roots ([1, 0, 0, 1])); %! assert (zc, complex (0.5, sin (pi/3)), 10*eps) %! assert (zr, -1, 2*eps) ## Test with 2 real zeros, one of them equal to 0 %!test %! [zc, zr] = cplxreal (roots ([1, 0, 0, 1, 0])); %! assert (zc, complex (0.5, sin (pi/3)), 10*eps) %! assert (zr, [-1; 0], 2*eps) ## Test with 3 real zeros, two of them equal to 0 %!test %! [zc, zr] = cplxreal (roots ([1, 0, 0, 1, 0, 0])); %! assert (zc, complex (0.5, sin (pi/3)), 10*eps) %! assert (zr, [-1; 0; 0], 2*eps) ## Test input validation %!error cplxreal () %!error cplxreal (1, 2, 3, 4) %!error cplxreal (1, ones (2, 3)) %!error cplxreal (1, -1) %!error cplxreal (1, [], 3) signal-1.4.5/inst/cpsd.m0000644000000000000000000000450214456505401013255 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{Pxx}, @var{freq}] =} cpsd (@var{x}, @var{y}) ## @deftypefnx {Function File} {[@dots{}] =} cpsd (@var{x}, @var{y}, @var{window}) ## @deftypefnx {Function File} {[@dots{}] =} cpsd (@var{x}, @var{y}, @var{window}, @var{overlap}) ## @deftypefnx {Function File} {[@dots{}] =} cpsd (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}) ## @deftypefnx {Function File} {[@dots{}] =} cpsd (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}) ## @deftypefnx {Function File} {[@dots{}] =} cpsd (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}, @var{range}) ## @deftypefnx {Function File} {} cpsd (@dots{}) ## ## Estimate cross power spectrum of data @var{x} and @var{y} by the Welch (1967) ## periodogram/FFT method. ## @seealso{pwelch} ## @end deftypefn function varargout = cpsd(varargin) ## Check fixed argument if (nargin < 2 || nargin > 7) print_usage (); endif nvarargin = length(varargin); ## remove any pwelch RESULT args and add 'cross' for iarg=1:nvarargin arg = varargin{iarg}; if ( ~isempty(arg) && ischar(arg) && ( strcmp(arg,'power') || ... strcmp(arg,'cross') || strcmp(arg,'trans') || ... strcmp(arg,'coher') || strcmp(arg,'ypower') )) varargin{iarg} = []; endif endfor varargin{nvarargin+1} = 'cross'; ## if ( nargout==0 ) pwelch(varargin{:}); elseif ( nargout==1 ) Pxx = pwelch(varargin{:}); varargout{1} = Pxx; elseif ( nargout>=2 ) [Pxx,f] = pwelch(varargin{:}); varargout{1} = Pxx; varargout{2} = f; endif endfunction signal-1.4.5/inst/csd.m0000644000000000000000000000406214456505401013076 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{Pxx},@var{freq}]} = csd(@var{x}, @var{y}, @var{Nfft}, @var{Fs}, @var{window}, @var{overlap}, @var{range}, @var{plot_type}, @var{detrend}) ## Estimate cross power spectrum of data "x" and "y" by the Welch (1967) ## periodogram/FFT method. ## ## Compatible with Matlab R11 csd and earlier. ## ## See "help pwelch" for description of arguments, hints and references ## --- especially hint (7) for Matlab R11 defaults. ## @end deftypefn function varargout = csd(varargin) ## Check fixed argument if ( nargin<2 ) error( 'csd: Need at least 2 args. Use help csd.' ); endif nvarargin = length(varargin); ## remove any pwelch RESULT args and add 'cross' for iarg=1:nvarargin arg = varargin{iarg}; if ( ~isempty(arg) && ischar(arg) && ( strcmp(arg,'power') || ... strcmp(arg,'cross') || strcmp(arg,'trans') || ... strcmp(arg,'coher') || strcmp(arg,'ypower') )) varargin{iarg} = []; endif endfor varargin{nvarargin+1} = 'cross'; ## saved_compatib = pwelch('R11-'); if ( nargout==0 ) pwelch(varargin{:}); elseif ( nargout==1 ) Pxx = pwelch(varargin{:}); varargout{1} = Pxx; elseif ( nargout>=2 ) [Pxx,f] = pwelch(varargin{:}); varargout{1} = Pxx; varargout{2} = f; endif pwelch(saved_compatib); endfunction signal-1.4.5/inst/czt.m0000644000000000000000000000660014456505401013125 0ustar0000000000000000## Copyright (C) 2004 Daniel Gunyan ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} czt (@var{x}) ## @deftypefnx {Function File} {} czt (@var{x}, @var{m}) ## @deftypefnx {Function File} {} czt (@var{x}, @var{m}, @var{w}) ## @deftypefnx {Function File} {} czt (@var{x}, @var{m}, @var{w}, @var{a}) ## Chirp z-transform. Compute the frequency response starting at a and ## stepping by w for m steps. a is a point in the complex plane, and ## w is the ratio between points in each step (i.e., radius increases ## exponentially, and angle increases linearly). ## ## To evaluate the frequency response for the range f1 to f2 in a signal ## with sampling frequency Fs, use the following: ## ## @example ## @group ## m = 32; ## number of points desired ## w = exp(-j*2*pi*(f2-f1)/((m-1)*Fs)); ## freq. step of f2-f1/m ## a = exp(j*2*pi*f1/Fs); ## starting at frequency f1 ## y = czt(x, m, w, a); ## @end group ## @end example ## ## If you don't specify them, then the parameters default to a Fourier ## transform: ## m=length(x), w=exp(-j*2*pi/m), a=1 ## ## If x is a matrix, the transform will be performed column-by-column. ## @end deftypefn ## Algorithm (based on Oppenheim and Schafer, "Discrete-Time Signal ## Processing", pp. 623-628): ## make chirp of length -N+1 to max(N-1,M-1) ## chirp => w^([-N+1:max(N-1,M-1)]^2/2) ## multiply x by chirped a and by N-elements of chirp, and call it g ## convolve g with inverse chirp, and call it gg ## pad ffts so that multiplication works ## ifft(fft(g)*fft(1/chirp)) ## multiply gg by M-elements of chirp and call it done function y = czt(x, m, w, a) if nargin < 1 || nargin > 4, print_usage; endif [row, col] = size(x); if row == 1, x = x(:); col = 1; endif if nargin < 2 || isempty(m), m = length(x(:,1)); endif if length(m) > 1, error("czt: m must be a single element\n"); endif if nargin < 3 || isempty(w), w = exp(-2*j*pi/m); endif if nargin < 4 || isempty(a), a = 1; endif if length(w) > 1, error("czt: w must be a single element\n"); endif if length(a) > 1, error("czt: a must be a single element\n"); endif ## indexing to make the statements a little more compact n = length(x(:,1)); N = [0:n-1]'+n; NM = [-(n-1):(m-1)]'+n; M = [0:m-1]'+n; nfft = 2^nextpow2(n+m-1); # fft pad W2 = w.^(([-(n-1):max(m-1,n-1)]'.^2)/2); # chirp for idx = 1:col fg = fft(x(:,idx).*(a.^-(N-n)).*W2(N), nfft); fw = fft(1./W2(NM), nfft); gg = ifft(fg.*fw, nfft); y(:,idx) = gg(M).*W2(M); endfor if row == 1, y = y.'; endif endfunction %!shared x %! x = [1,2,4,1,2,3,5,2,3,5,6,7,8,4,3,6,3,2,5,1]; %!assert(fft(x),czt(x),10000*eps); %!assert(fft(x'),czt(x'),10000*eps); %!assert(fft([x',x']),czt([x',x']),10000*eps); signal-1.4.5/inst/data2fun.m0000644000000000000000000001302714456505401014032 0ustar0000000000000000## Copyright (C) 2020 Juan Pablo Carbajal ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{fhandle}, @var{fullname}] =} data2fun (@var{ti}, @var{yi}) ## @deftypefnx {Function File} {[@dots{}] =} data2fun (@dots{}, @var{property}, @var{value}) ## Create a vectorized function based on data samples using interpolation. ## ## The values given in @var{yi} (N-by-k matrix) correspond to evaluations of the ## function y(t) at the points @var{ti} (N-by-1 matrix). ## The data is interpolated and the function handle to the generated interpolant ## is returned. ## ## The function accepts @var{property}-@var{value} pairs described below. ## ## @table @samp ## @item file ## Code is generated and .m file is created. The @var{value} contains the name ## of the function. The returned function handle is a handle to that file. If ## @var{value} is empty, then a name is automatically generated using ## @code{tempname} and the file is created in the current directory. @var{value} ## must not have an extension, since .m will be appended. ## Numerical values used in the function are stored in a .mat file with the same ## name as the function. ## ## @item interp ## Type of interpolation. See @code{interp1}. ## @end table ## ## @seealso{interp1} ## @end deftypefn function [fhandle, fullfname] = data2fun (t, y, varargin) if (nargin < 2 || mod (nargin, 2) != 0) print_usage (); endif ## Check input arguments interp_args = {"spline"}; given = struct ("file", false); if (! isempty (varargin)) ## Arguments interp_args = varargin; opt_args = fieldnames (given); [tf, idx] = ismember (opt_args, varargin); for i=1:numel (opt_args) given.(opt_args{i}) = tf(i); endfor if (given.file) ## FIXME: check that file will be in the path. Otherwise fhandle(0) fails. if (! isempty (varargin{idx(1)+1})) [dir, fname] = fileparts (varargin{idx(1)+1}); else [dir, fname] = fileparts (tempname (pwd (), "agen_")); endif interp_args(idx(1) + [0, 1]) = []; endif if (isempty (interp_args)) interp_args = {"spline"}; endif endif pp = interp1 (t, y, interp_args{end}, "pp"); if (given.file) fullfname = fullfile (dir, [fname, ".m"]); save ("-binary", [fullfname(1:end-2), ".mat"], "pp"); bodystr = [" persistent pp\n" ... " if (isempty (pp))\n" ... " pp = load ([mfilename(), \".mat\"]).pp;\n" ... " endif\n\n" ... " z = ppval (pp, x);"]; strfunc = generate_function_str (fname, {"z"}, {"x"}, bodystr); fid = fopen (fullfile (dir, [fname, ".m"]), "w"); fprintf (fid, "%s", strfunc); fclose (fid); fhandle = eval (["@", fname]); else fullfname = ""; fhandle = @(t_) ppval (pp, t_); endif endfunction function str = generate_function_str (name, oargs, iargs, bodystr) striargs = cell2mat (cellfun (@(x) [x ", "], iargs, "UniformOutput", false)); striargs = striargs(1:end-2); stroargs = cell2mat (cellfun (@(x) [x ", "], oargs, "UniformOutput", false)); stroargs = stroargs(1:end-2); if (! isempty (stroargs)) str = ["function [" stroargs "] = " name " (" striargs ")\n\n" ... bodystr "\n\nendfunction"]; else str = ["function " name " (" striargs ")\n\n" ... bodystr "\n\nendfunction"]; endif endfunction %!shared t, y %! t = linspace (0, 1, 10); %! y = t.^2 - 2*t + 1; %!test %! fhandle = data2fun (t, y); %! assert (y, fhandle (t)); %!test %! unwind_protect %! # Change to temporary folder in case tester cannot write current folder %! olddir = pwd(); %! cd(tempdir()); %! %! [fhandle fname] = data2fun (t, y, "file", "testdata2fun"); %! yt = testdata2fun (t); %! assert (y, yt); %! assert (y, fhandle (t)); %! unwind_protect_cleanup %! unlink (fname); %! unlink ([fname(1:end-2) ".mat"]); %! cd(olddir) %! end_unwind_protect %!test %! unwind_protect %! # Change to temporary folder in case tester cannot write current folder %! olddir = pwd(); %! cd(tempdir()); %! %! [fhandle fname] = data2fun (t, y, "file", ""); %! # generate commmand to execute using random file name %! cmd = sprintf ("yt = %s(t);", nthargout (2, @fileparts, fname)); %! eval (cmd); %! assert (y, yt); %! assert (y, fhandle (t)); %! unwind_protect_cleanup %! unlink (fname); %! unlink ([fname(1:end-2) ".mat"]); %! cd(olddir) %! end_unwind_protect %!test %! unwind_protect %! # Change to temporary folder in case tester cannot write current folder %! olddir = pwd(); %! cd(tempdir()); %! [fhandle fname] = data2fun (t, y, "file", "testdata2fun", "interp", "linear"); %! yt = testdata2fun (t); %! assert (y, yt); %! assert (y, fhandle (t)); %! unwind_protect_cleanup %! unlink (fname); %! unlink ([fname(1:end-2) ".mat"]); %! cd(olddir) %! end_unwind_protect ## Test input validation %!error data2fun () %!error data2fun (1) %!error data2fun (1, 2, "file") signal-1.4.5/inst/db2pow.m0000644000000000000000000000313614456505401013523 0ustar0000000000000000## Copyright (C) 2018 P Sudeepam ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} db2pow (@var{x}) ## Convert decibels (dB) to power. ## ## The power of @var{x} is defined as ## @tex ## $p = 10^{x/10}$. ## @end tex ## @ifnottex ## @var{p} = @code{10 ^ (x/10)}. ## @end ifnottex ## ## If @var{x} is a vector, matrix, or N-dimensional array, the power is ## computed over the elements of @var{x}. ## ## Example: ## ## @example ## @group ## db2pow ([-10, 0, 10]) ## @result{} 0.1000 1.0000 10.0000 ## @end group ## @end example ## @seealso{pow2db} ## @end deftypefn function y = db2pow (x) if (nargin != 1) print_usage (); endif y = 10 .^ (x ./ 10); endfunction %!shared db %! db = [-10, 0, 10, 20, 25]; %!assert (db2pow (db), [0.10000, 1.00000, 10.00000, 100.00000, 316.22777], 0.00001) %!assert (db2pow (db'), [0.10000; 1.00000; 10.00000; 100.00000; 316.22777], 0.00001) ## Test input validation %!error db2pow () %!error db2pow (1, 2) signal-1.4.5/inst/dct.m0000644000000000000000000000564314456505401013105 0ustar0000000000000000## Copyright (C) 2001 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} dct (@var{x}) ## @deftypefnx {Function File} {} dct (@var{x}, @var{n}) ## Compute the discrete cosine transform of @var{x}. If @var{n} is given, ## then @var{x} is padded or trimmed to length @var{n} before computing the ## transform. If @var{x} is a matrix, compute the transform along the columns ## of the the matrix. The transform is faster if @var{x} is real-valued and ## has even length. ## ## The discrete cosine transform @var{x} can be defined as follows: ## ## @example ## @group ## N-1 ## X[k] = w(k) sum x[n] cos (pi (2n+1) k / 2N ), k = 0, ..., N-1 ## n=0 ## @end group ## @end example ## ## with w(0) = sqrt(1/N) and w(k) = sqrt(2/N), k = 1, ..., N-1. There ## are other definitions with different scaling of X[k], but this form ## is common in image processing. ## ## @seealso{idct, dct2, idct2, dctmtx} ## @end deftypefn ## From Discrete Cosine Transform notes by Brian Evans at UT Austin, ## http://www.ece.utexas.edu/~bevans/courses/ee381k/lectures/09_DCT/lecture9/ ## the discrete cosine transform of x at k is as follows: ## ## N-1 ## X[k] = sum 2 x[n] cos (pi (2n+1) k / 2N ) ## n=0 ## ## which can be computed using: ## ## y = [ x ; flipud (x) ] ## Y = fft(y) ## X = exp( -j pi [0:N-1] / 2N ) .* Y ## ## or for real, even length x ## ## y = [ even(x) ; flipud(odd(x)) ] ## Y = fft(y) ## X = 2 real { exp( -j pi [0:N-1] / 2N ) .* Y } ## ## Scaling the result by w(k)/2 will give us the desired output. function y = dct (x, n) if (nargin < 1 || nargin > 2) print_usage; endif realx = isreal(x); transpose = (rows (x) == 1); if transpose, x = x (:); endif [nr, nc] = size (x); if nargin == 1 n = nr; elseif n > nr x = [ x ; zeros(n-nr,nc) ]; elseif n < nr x (nr-n+1 : n, :) = []; endif if n == 1 w = 1/2; else w = [ sqrt(1/4/n); sqrt(1/2/n)*exp((-1i*pi/2/n)*[1:n-1]') ] * ones (1, nc); endif if ( realx && rem (n, 2) == 0 ) y = fft ([ x(1:2:n,:) ; x(n:-2:1,:) ]); y = 2 * real( w .* y ); else y = fft ([ x ; flipud(x) ]); y = w .* y (1:n, :); if (realx) y = real (y); endif endif if transpose, y = y.'; endif endfunction signal-1.4.5/inst/dct2.m0000644000000000000000000000267214456505401013166 0ustar0000000000000000## Copyright (C) 2001 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} dct2 (@var{x}) ## @deftypefnx {Function File} {} dct2 (@var{x}, @var{m}, @var{n}) ## @deftypefnx {Function File} {} dct2 (@var{x}, [@var{m}, @var{n}]) ## Compute the 2-D discrete cosine transform of matrix @var{x}. If ## @var{m} and @var{n} are specified, the input is padded or trimmed ## to the desired size. ## @seealso{dct, idct, idct2} ## @end deftypefn function y = dct2 (x, m, n) if (nargin < 1 || nargin > 3) print_usage; endif if nargin == 1 [m, n] = size(x); elseif (nargin == 2) n = m(2); m = m(1); endif if m == 1 y = dct (x.', n).'; elseif n == 1 y = dct (x, m); else y = dct (dct (x, m).', n).'; endif endfunction signal-1.4.5/inst/dctmtx.m0000644000000000000000000000337014456505401013631 0ustar0000000000000000## Copyright (C) 2001 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} dctmtx (@var{n}) ## Return the DCT transformation matrix of size @var{n}-by-@var{n}. ## ## If A is an @var{n}-by-@var{n} matrix, then the following are true: ## ## @example ## @group ## T*A == dct(A), T'*A == idct(A) ## T*A*T' == dct2(A), T'*A*T == idct2(A) ## @end group ## @end example ## ## A DCT transformation matrix is useful for doing things like jpeg ## image compression, in which an 8x8 DCT matrix is applied to ## non-overlapping blocks throughout an image and only a subblock on the ## top left of each block is kept. During restoration, the remainder of ## the block is filled with zeros and the inverse transform is applied ## to the block. ## ## @seealso{dct, idct, dct2, idct2} ## @end deftypefn function T = dctmtx(n) if nargin != 1 print_usage; endif if n > 1 T = [ sqrt(1/n)*ones(1,n) ; ... sqrt(2/n)*cos((pi/2/n)*([1:n-1]'*[1:2:2*n])) ]; elseif n == 1 T = 1; else error ("dctmtx: n must be at least 1"); endif endfunction signal-1.4.5/inst/decimate.m0000644000000000000000000000770714456505401014111 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} decimate (@var{x}, @var{q}) ## @deftypefnx {Function File} {@var{y} =} decimate (@var{x}, @var{q}, @var{n}) ## @deftypefnx {Function File} {@var{y} =} decimate (@dots{}, "fir") ## ## Downsample the signal @var{x} by a reduction factor of @var{q}. A lowpass ## antialiasing filter is applied to the signal prior to reducing the input ## sequence. By default, an order @var{n} Chebyshev type I filter is used. ## If @var{n} is not specified, the default is 8. ## ## If the optional argument @code{"fir"} is given, an order @var{n} FIR filter ## is used, with a default order of 30 if @var{n} is not given. ## ## Note that @var{q} must be an integer for this rate change method. ## ## Example: ## @example ## ## Generate a signal that starts away from zero, is slowly varying ## ## at the start and quickly varying at the end, decimate and plot. ## ## Since it starts away from zero, you will see the boundary ## ## effects of the antialiasing filter clearly. Next you will see ## ## how it follows the curve nicely in the slowly varying early ## ## part of the signal, but averages the curve in the quickly ## ## varying late part of the signal. ## t = 0:0.01:2; ## x = chirp (t, 2, .5, 10, "quadratic") + sin (2*pi*t*0.4); ## y = decimate (x, 4); ## stem (t(1:121) * 1000, x(1:121), "-g;Original;"); hold on; # original ## stem (t(1:4:121) * 1000, y(1:31), "-r;Decimated;"); hold off; # decimated ## @end example ## @end deftypefn function y = decimate(x, q, n, ftype) if (nargin < 2 || nargin > 4) print_usage (); elseif (! (isscalar (q) && (q == fix (q)) && (q > 0))) error ("decimate: Q must be a positive integer"); endif if (nargin < 3) ftype = "iir"; n = []; elseif (nargin < 4) if (ischar (n)) ftype = n; n = []; else ftype = "iir"; endif endif if (! any (strcmp (ftype, {"fir", "iir"}))) error ('decimate: filter type must be either "fir" or "iir"'); endif fir = strcmp (ftype, "fir"); if (isempty (n)) if (fir) n = 30; else n = 8; endif endif if (! (isscalar (n) && (n == fix (n)) && (n > 0))) error ("decimate: N must be a positive integer"); endif if (fir) b = fir1 (n, 1/q); y = fftfilt (b, x); else [b, a] = cheby1 (n, 0.05, 0.8/q); y = filtfilt (b, a, x); endif y = y(1:q:length(x)); endfunction %!demo %! t=0:0.01:2; x=chirp(t,2,.5,10,'quadratic')+sin(2*pi*t*0.4); %! y = decimate(x,4); # factor of 4 decimation %! stem(t(1:121)*1000,x(1:121),"-g;Original;"); hold on; # plot original %! stem(t(1:4:121)*1000,y(1:31),"-r;Decimated;"); hold off; # decimated %! %------------------------------------------------------------------ %! % The signal to decimate starts away from zero, is slowly varying %! % at the start and quickly varying at the end, decimate and plot. %! % Since it starts away from zero, you will see the boundary %! % effects of the antialiasing filter clearly. You will also see %! % how it follows the curve nicely in the slowly varying early %! % part of the signal, but averages the curve in the quickly %! % varying late part of the signal. %% Test input validation %!error decimate () %!error decimate (1) %!error decimate (1, 2, 3, 4, 5) %!error decimate (1, -1) signal-1.4.5/inst/dftmtx.m0000644000000000000000000000262514456505401013636 0ustar0000000000000000## Copyright (C) 2003 David Bateman ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{d} =} dftmtx (@var{n}) ## Compute the @var{n}-by-@var{n} Fourier transformation matrix. This is ## the matrix @var{d} such that the Fourier transform of a column vector of ## length @var{n} is given by @code{dftmtx(@var{n}) * @var{x}} and the ## inverse Fourier transform is given by @code{inv(dftmtx(@var{n})) * @var{x}}. ## ## In general this is less efficient than calling the @code{fft} and ## @code{ifft} functions directly. ## @seealso{fft, ifft} ## @end deftypefn function d = dftmtx(n) if (nargin != 1) print_usage; elseif (!isscalar(n)) error ("dftmtx: argument must be scalar"); endif d = fft(eye(n)); endfunction signal-1.4.5/inst/digitrevorder.m0000644000000000000000000000505714456505401015203 0ustar0000000000000000## Copyright (C) 2013-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} digitrevorder (@var{x}, @var{r}) ## @deftypefnx {Function File} {[@var{y}, @var{i}] =} digitrevorder (@var{x}, @var{r}) ## Reorder the elements of the vector @var{x} in digit-reversed order. ## The elements of @var{x} are converted to radix @var{r} and reversed. ## The reordered indices of the elements of @var{x} are returned in @var{i}. ## @seealso{bitrevorder, fft, ifft} ## @end deftypefn function [y, i] = digitrevorder (x, r) if (nargin < 1 || nargin > 2) print_usage (); elseif (! isvector (x)) error ("digitrevorder: X must be a vector"); elseif (!(isscalar (r) && r == fix (r) && r >= 2 && r <= 36)) error ("digitrevorder: R must be an integer between 2 and 36"); else tmp = log (numel (x)) / log (r); if (fix (tmp) != tmp) error ("digitrevorder: X must have length equal to an integer power of %d", r); endif endif old_ind = 0:numel (x) - 1; new_ind = base2dec (fliplr (dec2base (old_ind, r)), r); i = new_ind + 1; y(old_ind + 1) = x(i); if (iscolumn (x)) y = y(:); else i = i.'; endif endfunction %!assert (digitrevorder (0, 2), 0); %!assert (digitrevorder (0, 36), 0); %!assert (digitrevorder (0:3, 4), 0:3); %!assert (digitrevorder ([0:3]', 4), [0:3]'); %!assert (digitrevorder (0:7, 2), [0 4 2 6 1 5 3 7]); %!assert (digitrevorder ([0:7]', 2), [0 4 2 6 1 5 3 7]'); %!assert (digitrevorder ([0:7]*i, 2), [0 4 2 6 1 5 3 7]*i); %!assert (digitrevorder ([0:7]'*i, 2), [0 4 2 6 1 5 3 7]'*i); %!assert (digitrevorder (0:15, 2), [0 8 4 12 2 10 6 14 1 9 5 13 3 11 7 15]); %!assert (digitrevorder (0:15, 4), [0 4 8 12 1 5 9 13 2 6 10 14 3 7 11 15]); %% Test input validation %!error digitrevorder (); %!error digitrevorder (1); %!error digitrevorder (1, 2, 3); %!error digitrevorder ([], 1); %!error digitrevorder ([], 37); %!error digitrevorder (0:3, 8); signal-1.4.5/inst/diric.m0000644000000000000000000000225014456505401013414 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} diric (@var{x},@var{n}) ## Compute the dirichlet function. ## @seealso{sinc, gauspuls, sawtooth} ## @end deftypefn function y = diric(x,n) if (nargin < 2) print_usage; elseif (n <= 0 || floor(n) ~= n) error("n must be an integer strictly positive"); endif y = sin(n.*x./2)./(n.*sin(x./2)); y(mod(x,2*pi)==0) = (-1).^((n-1).*x(mod(x,2*pi)==0)./(2.*pi)); endfunction signal-1.4.5/inst/downsample.m0000644000000000000000000000250414456505401014475 0ustar0000000000000000## Author: Paul Kienzle (2007) ## This program is granted to the public domain. ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} downsample (@var{x}, @var{n}) ## @deftypefnx {Function File} {@var{y} =} downsample (@var{x}, @var{n}, @var{offset}) ## Downsample the signal, selecting every @var{n}th element. If @var{x} ## is a matrix, downsample every column. ## ## For most signals you will want to use @code{decimate} instead since ## it prefilters the high frequency components of the signal and ## avoids aliasing effects. ## ## If @var{offset} is defined, select every @var{n}th element starting at ## sample @var{offset}. ## @seealso{decimate, interp, resample, upfirdn, upsample} ## @end deftypefn function y = downsample (x, n, phase = 0) if nargin<2 || nargin>3, print_usage; endif if phase > n - 1 warning("This is incompatible with Matlab (phase = 0:n-1). See octave-forge signal package release notes for details.") endif if isvector(x) y = x(phase + 1:n:end); else y = x(phase + 1:n:end,:); endif endfunction %!assert(downsample([1,2,3,4,5],2),[1,3,5]); %!assert(downsample([1;2;3;4;5],2),[1;3;5]); %!assert(downsample([1,2;3,4;5,6;7,8;9,10],2),[1,2;5,6;9,10]); %!assert(downsample([1,2,3,4,5],2,1),[2,4]); %!assert(downsample([1,2;3,4;5,6;7,8;9,10],2,1),[3,4;7,8]); signal-1.4.5/inst/dst.m0000644000000000000000000000266414456505401013125 0ustar0000000000000000## Author: Paul Kienzle (2006) ## This program is granted to the public domain. ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} dst (@var{x}) ## @deftypefnx {Function File} {@var{y} =} dst (@var{x}, @var{n}) ## Computes the type I discrete sine transform of @var{x}. If @var{n} is given, ## then @var{x} is padded or trimmed to length @var{n} before computing the transform. ## If @var{x} is a matrix, compute the transform along the columns of the ## the matrix. ## ## The discrete sine transform X of x can be defined as follows: ## ## @verbatim ## N ## X[k] = sum x[n] sin (pi n k / (N+1) ), k = 1, ..., N ## n=1 ## @end verbatim ## ## @seealso{idst} ## @end deftypefn function y = dst (x, n) if (nargin < 1 || nargin > 2) print_usage; endif transpose = (rows (x) == 1); if transpose, x = x (:); endif [nr, nc] = size (x); if nargin == 1 n = nr; elseif n > nr x = [ x ; zeros(n-nr,nc) ]; elseif n < nr x (nr-n+1 : n, :) = []; endif y = fft ([ zeros(1,nc); x ; zeros(1,nc); -flipud(x) ])/-2j; y = y(2:nr+1,:); if isreal(x), y = real (y); endif ## Compare directly against the slow transform ## y2 = x; ## w = pi*[1:n]'/(n+1); ## for k = 1:n, y2(k) = sum(x(:).*sin(k*w)); endfor ## y = [y,y2]; if transpose, y = y.'; endif endfunction %!test %! x = log(linspace(0.1,1,32)); %! y = dst(x); %! assert(y(3), sum(x.*sin(3*pi*[1:32]/33)), 100*eps) signal-1.4.5/inst/dwt.m0000644000000000000000000000357714456505401013135 0ustar0000000000000000## Copyright (C) 2013 Lukas F. Reichlin ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{u}, @var{v}] =} dwt (@var{x}, @var{wname}) ## @deftypefnx {Function File} {[@var{u}, @var{v}] =} dwt (@var{x}, @var{Hp}, @var{Gp}) ## @deftypefnx {Function File} {[@var{u}, @var{v}] =} dwt (@var{x}, @var{Hp}, @var{Gp}, @dots{}) ## Discrete wavelet transform (1D). ## ## @strong{Inputs} ## @table @var ## @item x ## Signal vector. ## @item wname ## Wavelet name. ## @item Hp ## Coefficients of low-pass decomposition @acronym{FIR} filter. ## @item Gp ## Coefficients of high-pass decomposition @acronym{FIR} filter. ## @end table ## ## @strong{Outputs} ## @table @var ## @item u ## Signal vector of average, approximation. ## @item v ## Signal vector of difference, detail. ## @end table ## @end deftypefn ## Author: Lukas Reichlin ## Created: April 2013 ## Version: 0.1 function [u, v] = dwt (x, varargin) if (nargin == 2) wname = varargin{1}; [Hp, Gp] = wfilters (wname, "d"); elseif (nargin == 3) Hp = varargin{1}; Gp = varargin{2}; else print_usage (); endif tmp = wconv (1, x, Hp, "valid"); u = tmp(1:2:end); tmp = wconv (1, x, Gp, "valid"); v = tmp(1:2:end); endfunction signal-1.4.5/inst/ellip.m0000644000000000000000000001335614456505401013440 0ustar0000000000000000## Copyright (C) 2001 Paulo Neis ## Copyright (C) 2003 Doug Stewart ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{b}, @var{a}] =} ellip (@var{n}, @var{rp}, @var{rs}, @var{wp}) ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} ellip (@var{n}, @var{rp}, @var{rs}, @var{wp}, "high") ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} ellip (@var{n}, @var{rp}, @var{rs}, @var{[wl}, @var{wh}]) ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} ellip (@var{n}, @var{rp}, @var{rs}, @var{[wl}, @var{wh}], "stop") ## @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} ellip (@dots{}) ## @deftypefnx {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} ellip (@dots{}) ## @deftypefnx {Function File} {[@dots{}] =} ellip (@dots{}, "s") ## ## Generate an elliptic or Cauer filter with @var{rp} dB of passband ripple and ## @var{rs} dB of stopband attenuation. ## ## [b,a] = ellip(n, Rp, Rs, Wp) ## low pass filter with order n, cutoff pi*Wp radians, Rp decibels ## of ripple in the passband and a stopband Rs decibels down. ## ## [b,a] = ellip(n, Rp, Rs, Wp, 'high') ## high pass filter with cutoff pi*Wp... ## ## [b,a] = ellip(n, Rp, Rs, [Wl, Wh]) ## band pass filter with band pass edges pi*Wl and pi*Wh ... ## ## [b,a] = ellip(n, Rp, Rs, [Wl, Wh], 'stop') ## band reject filter with edges pi*Wl and pi*Wh, ... ## ## [z,p,g] = ellip(...) ## return filter as zero-pole-gain. ## ## [...] = ellip(...,'s') ## return a Laplace space filter, W can be larger than 1. ## ## [a,b,c,d] = ellip(...) ## return state-space matrices ## ## References: ## ## - Oppenheim, Alan V., Discrete Time Signal Processing, Hardcover, 1999. ## - Parente Ribeiro, E., Notas de aula da disciplina TE498 - Processamento ## Digital de Sinais, UFPR, 2001/2002. ## @end deftypefn function [a, b, c, d] = ellip (n, rp, rs, w, varargin) if (nargin > 6 || nargin < 4 || nargout > 4) print_usage (); endif ## interpret the input parameters if (! (isscalar (n) && (n == fix (n)) && (n > 0))) error ("ellip: filter order N must be a positive integer"); endif stop = false; digital = true; for i = 1:numel (varargin) switch (varargin{i}) case "s" digital = false; case "z" digital = true; case {"high", "stop"} stop = true; case {"low", "pass"} stop = false; otherwise error ("ellip: expected [high|stop] or [s|z]"); endswitch endfor if (! ((numel (w) <= 2) && (rows (w) == 1 || columns (w) == 1))) error ("ellip: frequency must be given as WC or [WL, WH]"); elseif ((numel (w) == 2) && (w(2) <= w(1))) error ("ellip: W(1) must be less than W(2)"); endif if (digital && ! all ((w >= 0) & (w <= 1))) error ("ellip: all elements of W must be in the range [0,1]"); elseif (! digital && ! all (w >= 0)) error ("ellip: all elements of W must be in the range [0,inf]"); endif if (! (isscalar (rp) && isnumeric (rp) && (rp >= 0))) error ("ellip: passband ripple RP must be a non-negative scalar"); endif if (! (isscalar (rs) && isnumeric (rs) && (rs >= 0))) error ("ellip: stopband attenuation RS must be a non-negative scalar"); endif ## Prewarp the digital frequencies if (digital) T = 2; # sampling frequency of 2 Hz w = 2 / T * tan (pi * w / T); endif ## Generate s-plane poles, zeros and gain [zero, pole, gain] = ncauer (rp, rs, n); ## splane frequency transform [zero, pole, gain] = sftrans (zero, pole, gain, w, stop); ## Use bilinear transform to convert poles to the z plane if (digital) [zero, pole, gain] = bilinear (zero, pole, gain, T); endif ## convert to the correct output form ## note that poly always outputs a row vector if (nargout <= 2) a = real (gain * poly (zero)); b = real (poly (pole)); elseif (nargout == 3) a = zero(:); b = pole(:); c = gain; else ## output ss results [a, b, c, d] = zp2ss (zero, pole, gain); endif endfunction %!demo %! [n, Ws] = ellipord ([.1 .2], [.01 .4], 1, 90); %! [b, a] = ellip (5, 1, 90, [.1 .2]); %! [h, w] = freqz (b, a); %! %! plot (w./pi, 20*log10 (abs (h)), ";;") %! xlabel ("Frequency"); %! ylabel ("abs(H[w])[dB]"); %! axis ([0, 1, -100, 0]); %! %! hold ("on"); %! x=ones (1, length (h)); %! plot (w./pi, x.*-1, ";-1 dB;") %! plot (w./pi, x.*-90, ";-90 dB;") %! hold ("off"); %% Test input validation %!error [a, b] = ellip () %!error [a, b] = ellip (1) %!error [a, b] = ellip (1, 2) %!error [a, b] = ellip (1, 2, 3) %!error [a, b] = ellip (1, 2, 3, 4, 5, 6, 7) %!error [a, b] = ellip (.5, 2, 40, .2) %!error [a, b] = ellip (3, 2, 40, .2, "invalid") %% Test output orientation %!test %! ellip (6, 3, 50, .6); %! assert (isrow (ans)); %!test %! A = ellip (6, 3, 50, .6); %! assert (isrow (A)); %!test %! [A, B] = ellip (6, 3, 50, .6); %! assert (isrow (A)); %! assert (isrow (B)); %!test %! [z, p, g] = ellip (6, 3, 50, .6); %! assert (iscolumn (z)); %! assert (iscolumn (p)); %! assert (isscalar (g)); %!test %! [a, b, c, d] = ellip (6, 3, 50, .6); %! assert (ismatrix (a)); %! assert (iscolumn (b)); %! assert (isrow (c)); %! assert (isscalar (d)); signal-1.4.5/inst/ellipap.m0000644000000000000000000000314114456505401013750 0ustar0000000000000000## Copyright (C) 2013 CarnĂ« Draug ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} ellipap (@var{n}, @var{Rp}, @var{Rs}) ## Design lowpass analog elliptic filter. ## ## This function exists for @sc{matlab} compatibility only, and is equivalent ## to @code{ellip (@var{n}, @var{Rp}, @var{Rs}, 1, "s")}. ## ## @seealso{ellip} ## @end deftypefn function [z, p, g] = ellipap (n, Rp, Rs) if (nargin != 3) print_usage(); elseif (! isscalar (n) || ! isnumeric (n) || fix (n) != n || n <= 0) error ("ellipap: N must be a positive integer"); elseif (! isscalar (Rp) || ! isnumeric (Rp) || Rp <= 0) error ("ellipap: RP must be a positive scalar"); elseif (! isscalar (Rs) || ! isnumeric (Rs) || Rs < 0) error ("ellipap: RS must be a positive scalar"); elseif (Rp > Rs) error ("ellipap: RS must be larger than RP"); endif [z, p, g] = ellip (n, Rp, Rs, 1, "s"); endfunction signal-1.4.5/inst/ellipord.m0000644000000000000000000010273314456505401014143 0ustar0000000000000000## Copyright (C) 2001 Paulo Neis ## Copyright (C) 2018 Charles Praplan ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{n} =} ellipord (@var{wp}, @var{ws}, @var{rp}, @var{rs}) ## @deftypefnx {Function File} {@var{n} =} ellipord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}) ## @deftypefnx {Function File} {@var{n} =} ellipord ([@var{wp1}, @var{wp2}], [@var{ws1}, @var{ws2}], @var{rp}, @var{rs}, "s") ## @deftypefnx {Function File} {[@var{n}, @var{wc}] =} ellipord (@dots{}) ## Compute the minimum filter order of an elliptic filter with the desired ## response characteristics. The filter frequency band edges are specified ## by the passband frequency @var{wp} and stopband frequency @var{ws}. ## Frequencies are normalized to the Nyquist frequency in the range [0,1]. ## @var{rp} is the allowable passband ripple measured in decibels, and @var{rs} ## is the minimum attenuation in the stop band, also in decibels. The output ## arguments @var{n} and @var{wc} can be given as inputs to @code{ellip}. ## ## If @var{wp} and @var{ws} are scalars, then @var{wp} is the passband cutoff ## frequency and @var{ws} is the stopband edge frequency. If @var{ws} is ## greater than @var{wp}, the filter is a low-pass filter. If @var{wp} is ## greater than @var{ws}, the filter is a high-pass filter. ## ## If @var{wp} and @var{ws} are vectors of length 2, then @var{wp} defines the ## passband interval and @var{ws} defines the stopband interval. If @var{wp} ## is contained within @var{ws} (@var{ws1} < @var{wp1} < @var{wp2} < @var{ws2}), ## the filter is a band-pass filter. If @var{ws} is contained within @var{wp} ## (@var{wp1} < @var{ws1} < @var{ws2} < @var{wp2}), the filter is a band-stop ## or band-reject filter. ## ## If the optional argument @code{"s"} is given, the minimum order for an analog ## elliptic filter is computed. All frequencies @var{wp} and @var{ws} are ## specified in radians per second. ## ## Reference: Lamar, Marcus Vinicius, @cite{Notas de aula da disciplina TE 456 - ## Circuitos Analogicos II}, UFPR, 2001/2002. ## @seealso{buttord, cheb1ord, cheb2ord, ellip} ## @end deftypefn function [n, Wp] = ellipord (Wp, Ws, Rp, Rs, opt) if (nargin < 4 || nargin > 5) print_usage (); elseif (nargin == 5 && ! strcmp (opt, "s")) error ("ellipord: OPT must be the string \"s\""); endif if (nargin == 5 && strcmp (opt, "s")) s_domain = true; else s_domain = false; endif if (s_domain) validate_filter_bands ("ellipord", Wp, Ws, "s"); else validate_filter_bands ("ellipord", Wp, Ws); endif if (s_domain) # No prewarp in case of analog filter Wpw = Wp; Wsw = Ws; else ## sampling frequency of 2 Hz T = 2; Wpw = (2 / T) .* tan (pi .* Wp ./ T); # prewarp Wsw = (2 / T) .* tan (pi .* Ws ./ T); # prewarp endif ## pass/stop band to low pass filter transform: if (length (Wpw) == 2 && length (Wsw) == 2) ## Band-pass filter if (Wpw(1) > Wsw(1)) ## Modify band edges if not symmetrical. For a band-pass filter, ## the lower or upper stopband limit is moved, resulting in a smaller ## stopband than the caller requested. if ((Wpw(1) * Wpw(2)) < (Wsw(1) * Wsw(2))) Wsw(2) = Wpw(1) * Wpw(2) / Wsw(1); else Wsw(1) = Wpw(1) * Wpw(2) / Wsw(2); endif wp = Wpw(2) - Wpw(1); ws = Wsw(2) - Wsw(1); ## Band-stop / band-reject / notch filter else ## Modify band edges if not symmetrical. For a band-stop filter, ## the lower or upper passband limit is moved, resulting in a smaller ## rejection band than the caller requested. if ((Wpw(1) * Wpw(2)) > (Wsw(1) * Wsw(2))) Wpw(2) = Wsw(1) * Wsw(2) / Wpw(1); else Wpw(1) = Wsw(1) * Wsw(2) / Wpw(2); endif w02 = Wpw(1) * Wpw(2); wp = w02 / (Wpw(2) - Wpw(1)); ws = w02 / (Wsw(2) - Wsw(1)); endif ws = ws / wp; wp = 1; ## High-pass filter elseif (Wpw > Wsw) wp = Wsw; ws = Wpw; ## Low-pass filter else wp = Wpw; ws = Wsw; endif k = wp / ws; k1 = sqrt (1 - k^2); q0 = (1/2) * ((1 - sqrt (k1)) / (1 + sqrt (k1))); q = q0 + 2 * q0^5 + 15 * q0^9 + 150 * q0^13; #(....) D = (10 ^ (0.1 * Rs) - 1) / (10 ^ (0.1 * Rp) - 1); n = ceil (log10 (16 * D) / log10 (1 / q)); if (s_domain) # No prewarp in case of analog filter Wp = Wpw; else # Inverse frequency warping for discrete-time filter Wp = atan (Wpw .* (T / 2)) .* (T / pi); endif endfunction %!demo %! fs = 44100; %! Npts = fs; %! fpass = 4000; %! fstop = 13713; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn); %! f = 0:fs/2; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_lp_pass_x, outline_lp_pass_y, "m", outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("2nd order digital elliptical low-pass (without margin)"); %!demo %! fs = 44100; %! Npts = fs; %! fpass = 4000; %! fstop = 13712; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn); %! f = 0:fs/2; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_lp_pass_x, outline_lp_pass_y, "m", outline_lp_stop_x, outline_lp_stop_y, "m"); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("3rd order digital elliptical low-pass (just exceeds 2nd order i.e. large margin)"); %!demo %! fs = 44100; %! Npts = fs; %! fstop = 4000; %! fpass = 13713; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn, "high"); %! f = 0:fs/2; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [min(f) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_hp_pass_x, outline_hp_pass_y, "m", outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("2nd order digital elliptical high-pass (without margin)"); %!demo %! fs = 44100; %! Npts = fs; %! fstop = 4000; %! fpass = 13712; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn, "high"); %! f = 0:fs/2; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))); %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [min(f) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_hp_pass_x, outline_hp_pass_y, "m", outline_hp_stop_x, outline_hp_stop_y, "m"); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("3rd order digital elliptical high-pass (just exceeds 2nd order i.e. large margin)"); %!demo %! fs = 44100; %! Npts = fs; %! fpass = [9500 9750]; %! fstop = [8500 10261]; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn); %! f = 5000:15000; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m", outline_bp_stop_x, outline_bp_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("4th order digital elliptical band-pass (without margin) limitation on upper freq"); %!demo %! fs = 44100; %! Npts = fs; %! fpass = [9500 9750]; %! fstop = [9000 10700]; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn); %! f = 5000:15000; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m", outline_bp_stop_x, outline_bp_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("4th order digital elliptical band-pass (without margin) limitation on lower freq"); %!demo %! fs = 44100; %! Npts = fs; %! fpass = [9500 9750]; %! fstop = [8500 10260]; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn); %! f = 5000:15000; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m", outline_bp_stop_x, outline_bp_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("6th order digital elliptical band-pass (just exceeds 4th order i.e. large margin) limitation on upper freq"); %!demo %! fs = 44100; %! Npts = fs; %! fpass = [9500 9750]; %! fstop = [9001 10700]; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn); %! f = 5000:15000; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m", outline_bp_stop_x, outline_bp_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("6th order digital elliptical band-pass (just exceeds 4th order i.e. large margin) limitation on lower freq"); %!demo %! fs = 44100; %! Npts = fs; %! fstop = [9875 10126.5823]; %! fpass = [8500 11073]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn, "stop"); %! f = 5000:15000; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m", outline_notch_pass_x_b, outline_notch_pass_y_b, "m", outline_notch_stop_x, outline_notch_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("4th order digital elliptical notch (without margin) limit on upper freq"); %!demo %! fs = 44100; %! Npts = fs; %! fstop = [9875 10126.5823]; %! fpass = [8952 12000]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn, "stop"); %! f = 5000:15000; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m", outline_notch_pass_x_b, outline_notch_pass_y_b, "m", outline_notch_stop_x, outline_notch_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("4th order digital elliptical notch (without margin) limit on lower freq"); %!demo %! fs = 44100; %! Npts = fs; %! fstop = [9875 10126.5823]; %! fpass = [8500 11072]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn, "stop"); %! f = 5000:15000; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m", outline_notch_pass_x_b, outline_notch_pass_y_b, "m", outline_notch_stop_x, outline_notch_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("6th order digital elliptical notch (just exceeds 4th order) limit on upper freq"); %!demo %! fs = 44100; %! Npts = fs; %! fstop = [9875 10126.5823]; %! fpass = [8953 12000]; %! Rpass = 0.5; %! Rstop = 40; %! Wpass = 2/fs * fpass; %! Wstop = 2/fs * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop) %! [b, a] = ellip (n, Rpass, Rstop, Wn, "stop"); %! f = 5000:15000; %! W = f * (2 * pi / fs); %! H = freqz (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_notch_pass_x_a = [min(f) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [min(f) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m", outline_notch_pass_x_b, outline_notch_pass_y_b, "m", outline_notch_stop_x, outline_notch_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("6th order digital elliptical notch (just exceeds 4th order) limit on lower freq"); %!demo %! fpass = 4000; %! fstop = 20224; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "s"); %! f = 1000:10:100000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! semilogx(f, 20 * log10 (abs (H))) %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_lp_pass_x, outline_lp_pass_y, "m", outline_lp_stop_x, outline_lp_stop_y, "m") %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("2nd order analog elliptical low-pass (without margin)"); %!demo %! fpass = 4000; %! fstop = 20223; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "s"); %! f = 1000:10:100000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))) %! outline_lp_pass_x = [f(2) , fpass(1), fpass(1)]; %! outline_lp_pass_y = [-Rpass, -Rpass , -80]; %! outline_lp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_lp_stop_y = [0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_lp_pass_x, outline_lp_pass_y, "m", outline_lp_stop_x, outline_lp_stop_y, "m") %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("3rd order analog elliptical low-pass (just exceeds 2nd order i.e. large margin)"); %!demo %! fstop = 4000; %! fpass = 20224; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "high", "s"); %! f = 1000:10:100000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))) %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_hp_pass_x, outline_hp_pass_y, "m", outline_hp_stop_x, outline_hp_stop_y, "m") %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("2nd order analog elliptical high-pass (without margin)"); %!demo %! fstop = 4000; %! fpass = 20223; %! Rpass = 3; %! Rstop = 40; %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "high", "s"); %! f = 1000:10:100000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! semilogx (f, 20 * log10 (abs (H))) %! outline_hp_pass_x = [fpass(1), fpass(1), max(f)]; %! outline_hp_pass_y = [-80 , -Rpass , -Rpass]; %! outline_hp_stop_x = [f(2) , fstop(1), fstop(1), max(f)]; %! outline_hp_stop_y = [-Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_hp_pass_x, outline_hp_pass_y, "m", outline_hp_stop_x, outline_hp_stop_y, "m") %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("3rd order analog elliptical high-pass (just exceeds 2nd order i.e. large margin)"); %!demo %! fpass = [9875 10126.5823]; %! fstop = [9000 10657]; %! Rpass = 3; %! Rstop = 40; %! fcenter = sqrt (fpass(1) * fpass(2)); %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "s"); %! f = 5000:15000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m", outline_bp_stop_x, outline_bp_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("4th order analog elliptical band-pass (without margin) limitation on upper freq"); %!demo %! fpass = [9875 10126.5823]; %! fstop = [9384 12000]; %! Rpass = 3; %! Rstop = 40; %! fcenter = sqrt (fpass(1) * fpass(2)); %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "s"); %! f = 5000:15000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m", outline_bp_stop_x, outline_bp_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("4th order analog elliptical band-pass (without margin) limitation on lower freq"); %!demo %! fpass = [9875 10126.5823]; %! fstop = [9000 10656]; %! Rpass = 3; %! Rstop = 40; %! fcenter = sqrt (fpass(1) * fpass(2)); %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "s"); %! f = 5000:15000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m", outline_bp_stop_x, outline_bp_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("6th order analog elliptical band-pass (just exceeds 4th order i.e. large margin) limitation on upper freq"); %!demo %! fpass = [9875 10126.5823]; %! fstop = [9385 12000]; %! Rpass = 3; %! Rstop = 40; %! fcenter = sqrt (fpass(1) * fpass(2)); %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "s"); %! f = 5000:15000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_bp_pass_x = [fpass(1), fpass(1), fpass(2), fpass(2)]; %! outline_bp_pass_y = [-80 , -Rpass , -Rpass , -80]; %! outline_bp_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_bp_stop_y = [-Rstop , -Rstop , 0 , 0 , -Rstop , -Rstop]; %! hold on %! plot (outline_bp_pass_x, outline_bp_pass_y, "m", outline_bp_stop_x, outline_bp_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("6th order analog elliptical band-pass (just exceeds 4th order i.e. large margin) limitation on lower freq"); %!demo %! fstop = [9875 10126.5823]; %! fpass = [9000 10657]; %! Rpass = 3; %! Rstop = 40; %! fcenter = sqrt (fpass(1) * fpass(2)); %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "stop", "s"); %! f = 5000:15000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m", outline_notch_pass_x_b, outline_notch_pass_y_b, "m", outline_notch_stop_x, outline_notch_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("4th order analog elliptical notch (without margin) limit on upper freq"); %!demo %! fstop = [9875 10126.5823]; %! fpass = [9384 12000]; %! Rpass = 3; %! Rstop = 40; %! fcenter = sqrt (fpass(1) * fpass(2)); %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "stop", "s"); %! f = 5000:15000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m", outline_notch_pass_x_b, outline_notch_pass_y_b, "m", outline_notch_stop_x, outline_notch_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("4th order analog elliptical notch (without margin) limit on lower freq"); %!demo %! fstop = [9875 10126.5823]; %! fpass = [9000 10656]; %! Rpass = 3; %! Rstop = 40; %! fcenter = sqrt (fpass(1) * fpass(2)); %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "stop", "s"); %! f = 5000:15000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m", outline_notch_pass_x_b, outline_notch_pass_y_b, "m", outline_notch_stop_x, outline_notch_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("6th order analog elliptical notch (just exceeds 4th order) limit on upper freq"); %!demo %! fstop = [9875 10126.5823]; %! fpass = [9385 12000]; %! Rpass = 3; %! Rstop = 40; %! fcenter = sqrt (fpass(1) * fpass(2)); %! Wpass = 2*pi * fpass; %! Wstop = 2*pi * fstop; %! [n, Wn] = ellipord (Wpass, Wstop, Rpass, Rstop, "s") %! [b, a] = ellip (n, Rpass, Rstop, Wn, "stop", "s"); %! f = 5000:15000; %! W = 2*pi * f; %! H = freqs (b, a, W); %! plot (f, 20 * log10 (abs (H))) %! outline_notch_pass_x_a = [f(2) , fpass(1), fpass(1)]; %! outline_notch_pass_x_b = [fpass(2), fpass(2), max(f)]; %! outline_notch_pass_y_a = [-Rpass , -Rpass , -80]; %! outline_notch_pass_y_b = [-80 , -Rpass , -Rpass]; %! outline_notch_stop_x = [f(2) , fstop(1), fstop(1), fstop(2), fstop(2), max(f)]; %! outline_notch_stop_y = [0 , 0 , -Rstop , -Rstop , 0 , 0 ]; %! hold on %! plot (outline_notch_pass_x_a, outline_notch_pass_y_a, "m", outline_notch_pass_x_b, outline_notch_pass_y_b, "m", outline_notch_stop_x, outline_notch_stop_y, "m") %! xlim ([f(1), f(end)]); %! ylim ([-80, 0]); %! grid on %! xlabel ("Frequency (Hz)"); %! ylabel ("Attenuation (dB)"); %! title ("6th order analog elliptical notch (just exceeds 4th order) limit on lower freq"); %!test %! # Analog band-pass %! [n, Wn] = ellipord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9000, 10657], 3, 40, "s"); %! assert (n, 2); %! assert (round (Wn), [62046, 63627]); %!test %! # Analog band-pass %! [n, Wn] = ellipord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9384, 12000], 3, 40, "s"); %! assert (n, 2); %! assert (round (Wn), [62046, 63627]); %!test %! # Analog band-pass %! [n, Wn] = ellipord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9000, 10656], 3, 40, "s"); %! assert (n, 3); %! assert (round (Wn), [62046, 63627]); %!test %! # Analog band-pass %! [n, Wn] = ellipord (2 * pi * [9875, 10126.5823], ... %! 2 * pi * [9385, 12000], 3, 40, "s"); %! assert (n, 3); %! assert (round (Wn), [62046, 63627]); %!test %! # Analog high-pass %! [n, Wn] = ellipord (2 * pi * 20224, 2 * pi * 4000, 3, 40, "s"); %! assert (n, 2); %! assert (round (Wn), 127071); %!test %! # Analog high-pass %! [n, Wn] = ellipord (2 * pi * 20223, 2 * pi * 4000, 3, 40, "s"); %! assert (n, 3); %! assert (round (Wn), 127065); %!test %! # Analog low-pass %! [n, Wn] = ellipord (2 * pi * 4000, 2 * pi * 20224, 3, 40, "s"); %! assert (n, 2); %! assert (round (Wn), 25133); %!test %! # Analog low-pass %! [n, Wn] = ellipord (2 * pi * 4000, 2 * pi * 20223, 3, 40, "s"); %! assert (n, 3); %! assert (round (Wn), 25133); %!test %! # Analog notch (narrow band-stop) %! [n, Wn] = ellipord (2 * pi * [9000, 10657], ... %! 2 * pi * [9875, 10126.5823], 3, 40, "s"); %! assert (n, 2); %! assert (round (Wn), [58958, 66960]); %!test %! # Analog notch (narrow band-stop) %! [n, Wn] = ellipord (2 * pi * [9384, 12000], ... %! 2 * pi * [9875, 10126.5823], 3, 40, "s"); %! assert (n, 2); %! assert (round (Wn), [58961 , 66956]); %!test %! # Analog notch (narrow band-stop) %! [n, Wn] = ellipord (2 * pi * [9000, 10656], ... %! 2 * pi * [9875, 10126.5823], 3, 40, "s"); %! assert (n, 3); %! assert (round (Wn), [58964, 66954]); %!test %! # Analog notch (narrow band-stop) %! [n, Wn] = ellipord (2 * pi * [9385, 12000], ... %! 2 * pi * [9875, 10126.5823], 3, 40, "s"); %! assert (n, 3); %! assert (round (Wn), [58968, 66949]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * [9500, 9750], 2 / fs * [8500, 10261], 3, 40); %! Wn = Wn * fs / 2; %! assert (n, 2); %! assert (round (Wn), [9500, 9750]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * [9500, 9750], 2 / fs * [9000, 10700], 3, 40); %! Wn = Wn * fs / 2; %! assert (n, 2); %! assert (round (Wn), [9500, 9750]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * [9500, 9750], 2 / fs * [8500, 10260], 3, 40); %! Wn = Wn * fs / 2; %! assert (n, 3); %! assert (round (Wn), [9500, 9750]); %!test %! # Digital band-pass %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * [9500, 9750], 2 / fs * [9001, 10700], 3, 40); %! Wn = Wn * fs / 2; %! assert (n, 3); %! assert (round (Wn), [9500, 9750]); %!test %! # Digital high-pass %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * 13713, 2 / fs * 4000, 3, 40); %! Wn = Wn * fs / 2; %! assert (n, 2); %! assert (round (Wn), 13713); %!test %! # Digital high-pass %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * 13712, 2 / fs * 4000, 3, 40); %! Wn = Wn * fs / 2; %! assert (n, 3); %! assert (round (Wn), 13712); %!test %! # Digital low-pass %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * 4000, 2 / fs * 13713, 3, 40); %! Wn = Wn * fs / 2; %! assert (n, 2); %! assert (round (Wn), 4000); %!test %! # Digital low-pass %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * 4000, 2 / fs * 13712, 3, 40); %! Wn = Wn * fs / 2; %! assert (n, 3); %! assert (round (Wn), 4000); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * [8500, 11073], 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn = Wn * fs / 2; %! assert (n, 2); %! assert (round (Wn), [8952, 11073]); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * [8952, 12000], 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn = Wn * fs / 2; %! assert (n, 2); %! assert (round (Wn), [8952, 11073]); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * [8500, 11072], 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn = Wn * fs / 2; %! assert (n, 3); %! assert (round (Wn), [8953, 11072]); %!test %! # Digital notch (narrow band-stop) %! fs = 44100; %! [n, Wn] = ellipord (2 / fs * [8953, 12000], 2 / fs * [9875, 10126.5823], 0.5, 40); %! Wn = Wn * fs / 2; %! assert (n, 3); %! assert (round (Wn), [8953, 11072]); ## Test input validation %!error ellipord () %!error ellipord (.1) %!error ellipord (.1, .2) %!error ellipord (.1, .2, 3) %!error ellipord ([.1 .1], [.2 .2], 3, 4) %!error ellipord ([.1 .2], [.5 .6], 3, 4) %!error ellipord ([.1 .5], [.2 .6], 3, 4) signal-1.4.5/inst/fht.m0000644000000000000000000000417214456505401013110 0ustar0000000000000000## Copyright (C) 2008 Muthiah Annamalai ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{m} =} fht (@var{d}) ## @deftypefnx {Function File} {@var{m} =} fht (@var{d}, @var{n}) ## @deftypefnx {Function File} {@var{m} =} fht (@var{d}, @var{n}, @var{dim}) ## Calculate the Fast Hartley Transform of real input @var{d}. If @var{d} is ## a matrix, the Hartley transform is calculated along the columns by default. ## The options @var{n} and @var{dim} are similar to the options of FFT ## function. ## ## The forward and inverse Hartley transforms are the same (except for a ## scale factor of 1/N for the inverse Hartley transform), but ## implemented using different functions. ## ## The definition of the forward hartley transform for vector d, ## @math{ ## m[K] = \sum_{i=0}^{N-1} d[i]*(cos[K*2*pi*i/N] + sin[K*2*pi*i/N]), for 0 <= K < N. ## m[K] = \sum_{i=0}^{N-1} d[i]*CAS[K*i], for 0 <= K < N. } ## ## @example ## fht(1:4) ## @end example ## @seealso{ifht, fft} ## @end deftypefn function m = fht( d, n, dim ) if ( nargin < 1 ) print_usage(); endif if ( nargin == 3 ) Y = fft(d,n,dim); elseif ( nargin == 2 ) Y = fft(d,n); else Y = fft(d); endif m = real(Y) - imag(Y); ## -- Traditional -- ## N = length(d); ## for K = 1:N ## i = 0:N-1; ## t = 2*pi*(K-1).*i/N; ## ker = (cos(t) + sin(t)); ## val = dot(d,ker); ## m(K) = val; ## endfor endfunction %! %!assert( fht([1 2 3 4]),[10 -4 -2 0] ) %! signal-1.4.5/inst/filternorm.m0000644000000000000000000000565514456505401014517 0ustar0000000000000000## Copyright (C) 2023 Leonardo Araujo ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{L} = } filternorm (@var{b}, @var{a}) ## @deftypefnx {Function File} {@var{L} = } filternorm (@var{b}, @var{a}, @var{pnorm}) ## @deftypefnx {Function File} {@var{L} = } filternorm (@var{b}, @var{a}, 2, @var{tol}) ## ## Compute the 2-norm of a digital filter defined by the numerator coefficients, ## @var{b}, and the denominator coefficients, @var{a}. It is also possible to ## compute the infinity-norm by passing inf in the @var{pnorm} parameter. ## @var{pnorm} only accepts 2 or inf. ## ## Example: ## @example ## [b, a] = butter (8, 0.5); ## filternorm (b, a) ## @end example ## @end deftypefn function L = filternorm (b, a, pnorm, tol) if (nargin < 2 || nargin > 4 || ! isrow (b) || ! isrow (a)) print_usage; endif if nargin < 3 pnorm = 2; endif if pnorm != 2 && pnorm != Inf error ("pnorm should be either 2 or Inf") endif if nargin == 2 || pnorm == 2 # Parseval's theorem states that the L2-norm of a filter with frequency # response H(e^{j\omega}) is the square-root of the sum of the squares # of its filter impulse response (the energy of the impulse response). [h, _] = impz (b,a); L = sqrt (sum (h.^2)); % L = normp (h, pnorm); elseif pnorm == Inf # the norm in L-infinity is simply the maximum of the frequency response: # ||H||_{\infty} = \max_{0 \leq \omega \leq \pi} { |H(e^{j\omega})|} [H, W] = freqz (b, a, 1024); L = max (abs (H)); else error( "filternorm: pnorm must be either 2 or Inf" ); endif endfunction %!demo %! b = [1 0]; %! a = [1 1]; %! L = filternorm (b, a) %!demo %! [b, a] = butter(5, .5); %! L = filternorm (b, a) %! ## test input validation %!error n = filternorm () %!error n = filternorm (1) %!error n = filternorm (1, 1, 1) %!error n = filternorm (1, 1, 1, 1) %!error n = filternorm (1, 1, 1, 1, 1) %!error n = filternorm ([1:10]', 1) %!error n = filternorm (1, [1:10]') %!error n = filternorm ([1:10]', [1:10]') %!error n = filternorm (1:10, 1:10, 1:10) %!error n = filternorm (ones(3), ones(3)) %!test %! [b, a] = butter (5, .5); %! L = filternorm (b, a); %! assert (L, sqrt(2)/2, 1e-8) %!test %! [b, a] = butter (5, .5); %! Linf = filternorm (b, a, Inf); %! assert (Linf, 1, 1e-8); signal-1.4.5/inst/filtfilt.m0000644000000000000000000001056614456505401014150 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## Copyright (C) 2007 Francesco Potortì ## Copyright (C) 2008 Luca Citi ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} filtfilt (@var{b}, @var{a}, @var{x}) ## ## Forward and reverse filter the signal. This corrects for phase ## distortion introduced by a one-pass filter, though it does square the ## magnitude response in the process. That's the theory at least. In ## practice the phase correction is not perfect, and magnitude response ## is distorted, particularly in the stop band. ## ## Example ## @example ## @group ## [b, a]=butter(3, 0.1); # 5 Hz low-pass filter ## t = 0:0.01:1.0; # 1 second sample ## x=sin(2*pi*t*2.3)+0.25*randn(size(t)); # 2.3 Hz sinusoid+noise ## y = filtfilt(b,a,x); z = filter(b,a,x); # apply filter ## plot(t,x,';data;',t,y,';filtfilt;',t,z,';filter;') ## @end group ## @end example ## @end deftypefn ## FIXME: My version seems to have similar quality to matlab, ## but both are pretty bad. They do remove gross lag errors, though. function y = filtfilt(b, a, x) if (nargin != 3) print_usage; endif rotate = (size(x,1)==1); if rotate, # a row vector x = x(:); # make it a column vector endif lx = size(x,1); a = a(:).'; b = b(:).'; lb = length(b); la = length(a); n = max(lb, la); lrefl = 3 * (n - 1); if la < n, a(n) = 0; endif if lb < n, b(n) = 0; endif if (rows (x) <= lrefl) error ("filtfilt: X must be a vector or matrix with length greater than %d", lrefl); endif ## Compute a the initial state taking inspiration from ## Likhterov & Kopeika, 2003. "Hardware-efficient technique for ## minimizing startup transients in Direct Form II digital filters" kdc = sum(b) / sum(a); if (abs(kdc) < inf) # neither NaN nor +/- Inf si = fliplr(cumsum(fliplr(b - kdc * a))); else si = zeros(size(a)); # fall back to zero initialization endif si(1) = []; for (c = 1:size(x,2)) # filter all columns, one by one v = [2*x(1,c)-x((lrefl+1):-1:2,c); x(:,c); 2*x(end,c)-x((end-1):-1:end-lrefl,c)]; # a column vector ## Do forward and reverse filtering v = filter(b,a,v,si*v(1)); # forward filter v = flipud(filter(b,a,flipud(v),si*v(end))); # reverse filter y(:,c) = v((lrefl+1):(lx+lrefl)); endfor if (rotate) # x was a row vector y = rot90(y); # rotate it back endif endfunction %!error filtfilt (); %!error filtfilt (1, 2, 3, 4); %!error filtfilt ([0.28, 0.71, 0.28], 1, rand ()) %!error filtfilt ([0.28, 0.71, 0.28], 1, rand (6, 1)) %!test %! randn('state',0); %! r = randn(1,200); %! [b,a] = butter(10, [.2, .25]); %! yfb = filtfilt(b, a, r); %! assert (size(r), size(yfb)); %! assert (mean(abs(yfb)) < 1e3); %! assert (mean(abs(yfb)) < mean(abs(r))); %! ybf = fliplr(filtfilt(b, a, fliplr(r))); %! assert (mean(abs(ybf)) < 1e3); %! assert (mean(abs(ybf)) < mean(abs(r))); %!test %! randn('state',0); %! r = randn(1,1000); %! s = 10 * sin(pi * 4e-2 * (1:length(r))); %! [b,a] = cheby1(2, .5, [4e-4 8e-2]); %! y = filtfilt(b, a, r+s); %! assert (size(r), size(y)); %! assert (mean(abs(y)) < 1e3); %! assert (corr(s(250:750)(:), y(250:750)(:)) > .95) %! [b,a] = butter(2, [4e-4 8e-2]); %! yb = filtfilt(b, a, r+s); %! assert (mean(abs(yb)) < 1e3); %! assert (corr(y(:), yb(:)) > .99) %!test %! randn('state',0); %! r = randn(1,1000); %! s = 10 * sin(pi * 4e-2 * (1:length(r))); %! [b,a] = butter(2, [4e-4 8e-2]); %! y = filtfilt(b, a, [r.' s.']); %! yr = filtfilt(b, a, r); %! ys = filtfilt(b, a, s); %! assert (y, [yr.' ys.']); %! y2 = filtfilt(b.', a.', [r.' s.']); %! assert (y, y2); signal-1.4.5/inst/filtic.m0000644000000000000000000000753114456505401013603 0ustar0000000000000000## Copyright (C) 2004 David Billinghurst ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{zf} =} filtic (@var{b}, @var{a}, @var{y}) ## @deftypefnx {Function File} {@var{zf} =} filtic (@var{b}, @var{a}, @var{y}, @var{x}) ## ## Set initial condition vector for filter function ## The vector zf has the same values that would be obtained ## from function filter given past inputs x and outputs y ## ## The vectors x and y contain the most recent inputs and outputs ## respectively, with the newest values first: ## ## x = [x(-1) x(-2) ... x(-nb)], nb = length(b)-1 ## y = [y(-1) y(-2) ... y(-na)], na = length(a)-a ## ## If length(x)4 || nargin<3) || (nargout>1) print_usage; endif if nargin < 4, x = []; endif nz = max(length(a)-1,length(b)-1); zf=zeros(nz,1); ## Pad arrays a and b to length nz+1 if required if length(a)<(nz+1) a(length(a)+1:nz+1)=0; endif if length(b)<(nz+1) b(length(b)+1:nz+1)=0; endif ## Pad arrays x and y to length nz if required if length(x) < nz x(length(x)+1:nz)=0; endif if length(y) < nz y(length(y)+1:nz)=0; endif for i=nz:-1:1 for j=i:nz-1 zf(j) = b(j+1)*x(i) - a(j+1)*y(i)+zf(j+1); endfor zf(nz)=b(nz+1)*x(i)-a(nz+1)*y(i); endfor zf = zf ./ a(1); endfunction %!test %! ## Simple low pass filter %! b=[0.25 0.25]; %! a=[1.0 -0.5]; %! zf_ref=0.75; %! zf=filtic(b,a,[1.0],[1.0]); %! assert(zf,zf_ref,8*eps); %! %!test %! ## Simple high pass filter %! b=[0.25 -0.25]; %! a=[1.0 0.5]; %! zf_ref = [-0.25]; %! zf=filtic(b,a,[0.0],[1.0]); %! assert(zf,zf_ref,8*eps); %! %!test %! ## Second order cases %! [b,a]=butter(2,0.4); %! N=1000; ## Long enough for filter to settle %! xx=ones(1,N); %! [yy,zf_ref] = filter(b,a,xx); %! x=xx(N:-1:N-1); %! y=yy(N:-1:N-1); %! zf = filtic(b,a,y,x); %! assert(zf,zf_ref,8*eps); %! %! xx = cos(2*pi*linspace(0,N-1,N)/8); %! [yy,zf_ref] = filter(b,a,xx); %! x=xx(N:-1:N-1); %! y=yy(N:-1:N-1); %! zf = filtic(b,a,y,x); %! assert(zf,zf_ref,8*eps); %! %!test %! ## Third order filter - takes longer to settle %! N=10000; %! [b,a]=cheby1(3,10,0.5); %! xx=ones(1,N); %! [yy,zf_ref] = filter(b,a,xx); %! x=xx(N:-1:N-2); %! y=yy(N:-1:N-2); %! zf = filtic(b,a,y,x); %! assert(zf,zf_ref,8*eps); %! %!test %! ## Eight order high pass filter %! N=10000; %! [b,a]=butter(8,0.2); %! xx = cos(2*pi*linspace(0,N-1,N)/8); %! [yy,zf_ref] = filter(b,a,xx); %! x=xx(N:-1:N-7); %! y=yy(N:-1:N-7); %! zf = filtic(b,a,y,x); %! assert(zf,zf_ref,8*eps); %! %!test %! ## Case with 3 args %! [b,a]=butter(2,0.4); %! N=100; %! xx=[ones(1,N) zeros(1,2)]; %! [yy,zf_ref] = filter(b,a,xx); %! y=[yy(N+2) yy(N+1)]; %! zf=filtic(b,a,y); %! assert(zf,zf_ref,8*eps); ## Case when a(1) != 1 %!test %! a = [2, -3, 1]; %! b = [4, -3]; %! y = [0; 1]; %! z = filtic (b, a, y); %! assert (z, [-0.5; 0]); signal-1.4.5/inst/filtord.m0000644000000000000000000000476314456505401014000 0ustar0000000000000000## Copyright (C) 2023 Leonardo Araujo ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{n} = } filtord (@var{b}, @var{a}) ## @deftypefnx {Function File} {@var{n} = } filtord (@var{sos}) ## ## Returns the filter order @var{n} for a filter defined by the numerator ## coefficients, @var{b}, and the denominator coefficients, @var{a}. ## It also accepts a filter defined by a matrix of second-order sections, ## @var{sos}. ## ## Example: ## @example ## [b, a] = butter (8, 0.5); ## filtord (b, a) ## @end example ## @end deftypefn function n = filtord (b, a) if (nargin < 1 || nargin > 2) || ( nargin == 2 && ( ! isrow (b) || ! isrow (a) ) ) print_usage; endif if (nargin == 1 && isrow (b)) a = 1; endif if isrow (b) n = max ( length (b)-1, length (a)-1 ); else n = (size (b, 1) - 1) * 2 + max (sum (b(end,1:3) != 0) , sum (b(end,4:6) != 0)) - 1; endif endfunction %!demo %! b = [1 0]; %! a = [1 1]; %! n = filtord (b, a) %!demo %! b = [1 0 0 0 0 0 0 1]; %! a = [1 0 0 0 0 0 0 .5]; %! [sos, g] = tf2sos (b, a); %! n = filtord (sos) %! ## test input validation %!error n = filtord () %!error n = filtord (1, 1, 1) %!error n = filtord ([1:10]', 1) %!error n = filtord (1, [1:10]') %!error n = filtord ([1:10]', [1:10]') %!error n = filtord (1:10, 1:10, 1:10) %!error n = filtord (ones(3), ones(3)) %!test %! b = [1 0 0]; %! a = [1 0 0 0]; %! n = filtord (b, a); %! assert (n, 3, 1e-6) %!test %! [b, a] = butter (5, .5); %! n = filtord (b, a); %! assert (n, 5, 1e-6) %!test %! [b, a] = butter (6, .5); %! n = filtord (b, a); %! assert (n, 6, 1e-6) %!test %! b = [1 0 0 0 0 0 1]; %! a = [1 0 0 0 0 0 .5]; %! [sos, g] = tf2sos (b, a); %! n = filtord (sos); %! assert (n, 6, 1e-6) %!test %! b = [1 0 0 0 0 0 0 1]; %! a = [1 0 0 0 0 0 0 .5]; %! [sos, g] = tf2sos (b, a); %! n = filtord (sos); %! assert (n, 7, 1e-6) signal-1.4.5/inst/findpeaks.m0000644000000000000000000003231514456505401014273 0ustar0000000000000000## Copyright (C) 2012 Juan Pablo Carbajal ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{pks}, @var{loc}, @var{extra}] =} findpeaks (@var{data}) ## @deftypefnx {Function File} {@dots{} =} findpeaks (@dots{}, @var{property}, @var{value}) ## @deftypefnx {Function File} {@dots{} =} findpeaks (@dots{}, @asis{"DoubleSided"}) ## Finds peaks on @var{data}. ## ## Peaks of a positive array of data are defined as local maxima. For ## double-sided data, they are maxima of the positive part and minima of ## the negative part. @var{data} is expected to be a single column ## vector. ## ## The function returns the value of @var{data} at the peaks in ## @var{pks}. The index indicating their position is returned in ## @var{loc}. ## ## The third output argument is a structure with additional information: ## ## @table @asis ## @item "parabol" ## A structure containing the parabola fitted to each returned peak. The ## structure has two fields, @asis{"x"} and @asis{"pp"}. The field ## @asis{"pp"} contains the coefficients of the 2nd degree polynomial ## and @asis{"x"} the extrema of the interval where it was fitted. ## ## @item "height" ## The estimated height of the returned peaks (in units of @var{data}). ## ## @item "baseline" ## The height at which the roots of the returned peaks were calculated ## (in units of @var{data}). ## ## @item "roots" ## The abscissa values (in index units) at which the parabola fitted to ## each of the returned peaks realizes its width as defined below. ## @end table ## ## This function accepts property-value pair given in the list below: ## ## @table @asis ## ## @item "MinPeakHeight" ## Minimum peak height (non-negative scalar). Only peaks that exceed this ## value will be returned. For data taking positive and negative values ## use the option "DoubleSided". Default value @code{eps}. ## ## @item "MinPeakDistance" ## Minimum separation between (positive integer). Peaks separated by ## less than this distance are considered a single peak. This distance ## is also used to fit a second order polynomial to the peaks to ## estimate their width, therefore it acts as a smoothing parameter. ## The neighborhood size is equal to the value of @asis{"MinPeakDistance"}. ## Default value 1. ## ## @item "MinPeakWidth" ## Minimum width of peaks (positive integer). The width of the peaks is ## estimated using a parabola fitted to the neighborhood of each peak. ## The width is caulculated with the formula ## @group ## a * (width - x0)^2 = 1 ## @end group ## where a is the the concavity of the parabola and x0 its vertex. ## Default value 1. ## ## @item "MaxPeakWidth" ## Maximum width of peaks (positive integer). ## Default value @code{Inf}. ## ## @item "DoubleSided" ## Tells the function that data takes positive and negative values. The ## base-line for the peaks is taken as the mean value of the function. ## This is equivalent as passing the absolute value of the data after ## removing the mean. ## @end table ## ## Run @command{demo findpeaks} to see some examples. ## @end deftypefn function [pks idx varargout] = findpeaks (data, varargin) if (nargin < 1) print_usage (); endif if (! (isvector (data) && numel (data) >= 3)) error ("findpeaks:InvalidArgument", "findpeaks: DATA must be a vector of at least 3 elements"); endif transpose = (rows (data) == 1); if (transpose) data = data.'; endif ## --- Parse arguments --- # __data__ = abs (detrend (data, 0)); posscal = @(x) isscalar (x) && x >= 0; ## FIXME: inputParser was first implemented in the general package in the ## old @class type. This allowed for a very similar interface to ## Matlab but not quite equal. classdef was then implemented in ## Octave 4.0 release, which enabled inputParser to be implemented ## properly. However, this causes problem because we don't know ## what implementation may be running. A new version of the general ## package is being released to avoid the two implementations to ## co-exist. ## ## To keep supporting older octave versions, we have an alternative ## path that avoids inputParser. And if inputParser is available, ## we check what implementation is, and act accordingly. ## Note that in Octave 4.0, inputParser is classdef and Octave behaves ## weird for it. which ("inputParser") will return empty (thinks its a ## builtin function). if (exist ("inputParser") == 2 && isempty (strfind (which ("inputParser"), ["@inputParser" filesep "inputParser.m"]))) ## making use of classdef's inputParser .. parser = inputParser (); parser.FunctionName = "findpeaks"; parser.addParamValue ("MinPeakHeight", eps,posscal); parser.addParamValue ("MinPeakDistance", 1, posscal); parser.addParamValue ("MinPeakWidth", 1, posscal); parser.addParamValue ("MaxPeakWidth", Inf, posscal); parser.addSwitch ("DoubleSided"); parser.parse (varargin{:}); minH = parser.Results.MinPeakHeight; minD = parser.Results.MinPeakDistance; minW = parser.Results.MinPeakWidth; maxW = parser.Results.MaxPeakWidth; dSided = parser.Results.DoubleSided; else ## either old @inputParser or no inputParser at all... lvarargin = lower (varargin); ds = strcmpi (lvarargin, "DoubleSided"); if (any (ds)) dSided = true; lvarargin(ds) = []; else dSided = false; endif [~, minH, minD, minW, maxW] = parseparams (lvarargin, "minpeakheight", eps, "minpeakdistance", 1, "minpeakwidth", 1, "maxpeakwidth", Inf); if (! posscal (minH)) error ("findpeaks: MinPeakHeight must be a positive scalar"); elseif (! posscal (minD)) error ("findpeaks: MinPeakDistance must be a positive scalar"); elseif (! posscal (minW)) error ("findpeaks: MinPeakWidth must be a positive scalar"); elseif (! posscal (maxW)) error ("findpeaks: MaxPeakWidth must be a positive scalar"); endif endif if (dSided) [data, __data__] = deal (__data__, data); elseif (min (data) < 0) error ("findpeaks:InvalidArgument", 'Data contains negative values. You may want to "DoubleSided" option'); endif ## Rough estimates of first and second derivative df1 = diff (data, 1)([1; (1:end).']); df2 = diff (data, 2)([1; 1; (1:end).']); ## check for changes of sign of 1st derivative and negativity of 2nd ## derivative. ## <= in 1st derivative includes the case of oversampled signals. idx = find (df1.*[df1(2:end); 0] <= 0 & [df2(2:end); 0] < 0); ## Get peaks that are beyond given height tf = data(idx) > minH; idx = idx(tf); ## sort according to magnitude [~, tmp] = sort (data(idx), "descend"); idx_s = idx(tmp); ## Treat peaks separated less than minD as one D = abs (bsxfun (@minus, idx_s, idx_s.')); D += diag(NA(1,size(D,1))); # eliminate diagonal cpmparison if (any (D(:) < minD)) i = 1; peak = cell (); node2visit = 1:size(D,1); visited = []; idx_pruned = idx_s; ## debug ## h = plot(1:length(data),data,"-",idx_s,data(idx_s),'.r',idx_s,data(idx_s),'.g'); ## set(h(3),"visible","off"); while (! isempty (node2visit)) d = D(node2visit(1),:); visited = [visited node2visit(1)]; node2visit(1) = []; neighs = setdiff (find (d < minD), visited); if (! isempty (neighs)) ## debug ## set(h(3),"xdata",idx_s(neighs),"ydata",data(idx_s(neighs)),"visible","on") ## pause(0.2) ## set(h(3),"visible","off"); idx_pruned = setdiff (idx_pruned, idx_s(neighs)); visited = [visited neighs]; node2visit = setdiff (node2visit, visited); ## debug ## set(h(2),"xdata",idx_pruned,"ydata",data(idx_pruned)) ## pause endif endwhile idx = idx_pruned; endif extra = struct ("parabol", [], "height", [], "baseline", [], "roots", []); ## Estimate widths of peaks and filter for: ## width smaller than given. ## wrong concavity. ## not high enough ## data at peak is lower than parabola by 1% ## position of extrema minus center is bigger equal than minD/2 ## debug ## h = plot(1:length(data),data,"-",idx,data(idx),'.r',... ## idx,data(idx),'og',idx,data(idx),'-m'); ## set(h(4),"linewidth",2) ## set(h(3:4),"visible","off"); idx_pruned = idx; n = numel (idx); np = numel (data); struct_count = 0; for i=1:n ind = (floor (max(idx(i)-minD/2,1)) : ... ceil (min(idx(i)+minD/2,np))).'; pp = zeros (1,3); # If current peak is not local maxima, then fit parabola to neighbor if any (data(idx(i)-1) == data(idx(i))) # sample on left same as peak xm = 0; pp = ones (1,3); elseif any (data(ind) > data(idx(i))) pp = polyfit (ind, data(ind), 2); xm = -pp(2)^2 / (2*pp(1)); # position of extrema H = polyval (pp, xm); # value at extrema else # use it as vertex of parabola H = data(idx(i)); xm = idx(i); pp = zeros (1,3); pp(1) = (ind-xm).^2 \ (data(ind)-H); pp(2) = - 2 * pp(1) * xm; pp(3) = H + pp(1) * xm^2; endif ## debug # x = linspace(ind(1)-1,ind(end)+1,10); # set(h(4),"xdata",x,"ydata",polyval(pp,x),"visible","on") # set(h(3),"xdata",ind,"ydata",data(ind),"visible","on") # pause(0.2) # set(h(3:4),"visible","off"); # thrsh = min (data(ind([1 end]))); # rz = roots ([pp(1:2) pp(3)-thrsh]); # width = abs (diff (rz)); width = sqrt (abs(1 / pp(1))) + xm; if ( (width > maxW || width < minW) || ... pp(1) > 0 || ... H < minH || ... data(idx(i)) < 0.99*H || ... abs (idx(i) - xm) > minD/2) idx_pruned = setdiff (idx_pruned, idx(i)); elseif (nargout > 2) struct_count++; extra.parabol(struct_count).x = ind([1 end]); extra.parabol(struct_count).pp = pp; extra.roots(struct_count,1:2)= xm + [-width width]/2; extra.height(struct_count) = H; extra.baseline(struct_count) = mean ([H minH]); endif ## debug ## set(h(2),"xdata",idx_pruned,"ydata",data(idx_pruned)) ## pause(0.2) endfor idx = idx_pruned; if (dSided) pks = __data__(idx); else pks = data(idx); endif if (transpose) pks = pks.'; idx = idx.'; endif if (nargout() > 2) varargout{1} = extra; endif endfunction %!demo %! t = 2*pi*linspace(0,1,1024)'; %! y = sin(3.14*t) + 0.5*cos(6.09*t) + 0.1*sin(10.11*t+1/6) + 0.1*sin(15.3*t+1/3); %! %! data1 = abs(y); # Positive values %! [pks idx] = findpeaks(data1); %! %! data2 = y; # Double-sided %! [pks2 idx2] = findpeaks(data2,"DoubleSided"); %! [pks3 idx3] = findpeaks(data2,"DoubleSided","MinPeakHeight",0.5); %! %! subplot(1,2,1) %! plot(t,data1,t(idx),data1(idx),'xm') %! axis tight %! subplot(1,2,2) %! plot(t,data2,t(idx2),data2(idx2),"xm;>2*std;",t(idx3),data2(idx3),"or;>0.1;") %! axis tight %! legend("Location","NorthOutside","Orientation","horizontal") %! %! #---------------------------------------------------------------------------- %! # Finding the peaks of smooth data is not a big deal! %!demo %! t = 2*pi*linspace(0,1,1024)'; %! y = sin(3.14*t) + 0.5*cos(6.09*t) + 0.1*sin(10.11*t+1/6) + 0.1*sin(15.3*t+1/3); %! %! data = abs(y + 0.1*randn(length(y),1)); # Positive values + noise %! [pks idx] = findpeaks(data,"MinPeakHeight",1); %! %! dt = t(2)-t(1); %! [pks2 idx2] = findpeaks(data,"MinPeakHeight",1,... %! "MinPeakDistance",round(0.5/dt)); %! %! subplot(1,2,1) %! plot(t,data,t(idx),data(idx),'or') %! subplot(1,2,2) %! plot(t,data,t(idx2),data(idx2),'or') %! %! #---------------------------------------------------------------------------- %! # Noisy data may need tuning of the parameters. In the 2nd example, %! # MinPeakDistance is used as a smoother of the peaks. %!assert (isempty (findpeaks ([1, 1, 1]))) %!assert (isempty (findpeaks ([1; 1; 1]))) ## Test for bug #45056 %!test %! ## Test input vector is an oversampled sinusoid with clipped peaks %! x = min (3, cos (2*pi*[0:8000] ./ 600) + 2.01); %! assert (! isempty (findpeaks (x))) ## Test for bug #63987 %!test %! x = [1 10 2 2 1 9 1]; %! [pks, loc] = findpeaks(x); %! assert (loc, [2 6]) %! assert (pks, [10 9]) %% Test input validation %!error findpeaks () %!error findpeaks (1) %!error findpeaks ([1, 2]) ## Test Matlab compatibility %!test assert (findpeaks ([34 134 353 64 134 14 56 67 234 143 64 575 8657]), %! [353 134 234]) signal-1.4.5/inst/fir1.m0000644000000000000000000001555314456505401013175 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{b} =} fir1 (@var{n}, @var{w}) ## @deftypefnx {Function File} {@var{b} =} fir1 (@var{n}, @var{w}, @var{type}) ## @deftypefnx {Function File} {@var{b} =} fir1 (@var{n}, @var{w}, @var{type}, @var{window}) ## @deftypefnx {Function File} {@var{b} =} fir1 (@var{n}, @var{w}, @var{type}, @var{window}, @var{noscale}) ## ## Produce an order @var{n} FIR filter with the given frequency cutoff @var{w}, ## returning the @var{n}+1 filter coefficients in @var{b}. If @var{w} is a ## scalar, it specifies the frequency cutoff for a lowpass or highpass filter. ## If @var{w} is a two-element vector, the two values specify the edges of a ## bandpass or bandstop filter. If @var{w} is an N-element vector, each ## value specifies a band edge of a multiband pass/stop filter. ## ## The filter @var{type} can be specified with one of the following strings: ## "low", "high", "stop", "pass", "bandpass", "DC-0", or "DC-1". The default ## is "low" is @var{w} is a scalar, "pass" if @var{w} is a pair, or "DC-0" if ## @var{w} is a vector with more than 2 elements. ## ## An optional shaping @var{window} can be given as a vector with length ## @var{n}+1. If not specified, a Hamming window of length @var{n}+1 is used. ## ## With the option "noscale", the filter coefficients are not normalized. The ## default is to normalize the filter such that the magnitude response of the ## center of the first passband is 1. ## ## To apply the filter, use the return vector @var{b} with the @code{filter} ## function, for example @code{y = filter (b, 1, x)}. ## ## Examples: ## @example ## freqz (fir1 (40, 0.3)); ## freqz (fir1 (15, [0.2, 0.5], "stop")); # note the zero-crossing at 0.1 ## freqz (fir1 (15, [0.2, 0.5], "stop", "noscale")); ## @end example ## @seealso{filter, fir2} ## @end deftypefn ## FIXME: Consider using exact expression (in terms of sinc) for the ## impulse response rather than relying on fir2. ## FIXME: Find reference to the requirement that order be even for ## filters that end high. Figure out what to do with the ## window in these cases function b = fir1(n, w, varargin) if nargin < 2 || nargin > 5 print_usage; endif ## Assign default window, filter type and scale. ## If single band edge, the first band defaults to a pass band to ## create a lowpass filter. If multiple band edges, the first band ## defaults to a stop band so that the two band case defaults to a ## band pass filter. Ick. window = []; scale = 1; ftype = (length(w)==1); ## sort arglist, normalize any string for i=1:length(varargin) arg = varargin{i}; if ischar(arg), arg=lower(arg);endif if isempty(arg) continue; endif # octave bug---can't switch on [] switch arg case {'low','stop','dc-1'}, ftype = 1; case {'high','pass','bandpass','dc-0'}, ftype = 0; case {'scale'}, scale = 1; case {'noscale'}, scale = 0; otherwise window = arg; endswitch endfor ## build response function according to fir2 requirements bands = length(w)+1; f = zeros(1,2*bands); f(1) = 0; f(2*bands)=1; f(2:2:2*bands-1) = w; f(3:2:2*bands-1) = w; m = zeros(1,2*bands); m(1:2:2*bands) = rem([1:bands]-(1-ftype),2); m(2:2:2*bands) = m(1:2:2*bands); ## Increment the order if the final band is a pass band. Something ## about having a nyquist frequency of zero causing problems. if rem(n,2)==1 && m(2*bands)==1, warning("n must be even for highpass and bandstop filters. Incrementing."); n = n+1; if isvector(window) && isreal(window) && !ischar(window) ## Extend the window using interpolation M = length(window); if M == 1, window = [window; window]; elseif M < 4 window = interp1(linspace(0,1,M),window,linspace(0,1,M+1),'linear'); else window = interp1(linspace(0,1,M),window,linspace(0,1,M+1),'spline'); endif endif endif ## compute the filter b = fir2(n, f, m, [], 2, window); ## normalize filter magnitude if scale == 1 ## find the middle of the first band edge ## find the frequency of the normalizing gain if m(1) == 1 ## if the first band is a passband, use DC gain w_o = 0; elseif f(4) == 1 ## for a highpass filter, ## use the gain at half the sample frequency w_o = 1; else ## otherwise, use the gain at the center ## frequency of the first passband w_o = f(3) + (f(4)-f(3))/2; endif ## compute |h(w_o)|^-1 renorm = 1/abs(polyval(b, exp(-1i*pi*w_o))); ## normalize the filter b = renorm*b; endif endfunction %!demo %! freqz(fir1(40,0.3)); %!demo %! freqz(fir1(15,[0.2, 0.5], 'stop')); # note the zero-crossing at 0.1 %!demo %! freqz(fir1(15,[0.2, 0.5], 'stop', 'noscale')); %!assert(fir1(2, .5, 'low', @hanning, 'scale'), [0 1 0]); %!assert(fir1(2, .5, 'low', "hanning", 'scale'), [0 1 0]); %!assert(fir1(2, .5, 'low', hanning(3), 'scale'), [0 1 0]); %!assert(fir1(10,.5,'noscale'), fir1(10,.5,'low','hamming','noscale')); %!assert(fir1(10,.5,'high'), fir1(10,.5,'high','hamming','scale')); %!assert(fir1(10,.5,'boxcar'), fir1(10,.5,'low','boxcar','scale')); %!assert(fir1(10,.5,'hanning','scale'), fir1(10,.5,'scale','hanning','low')); %!assert(fir1(10,.5,'haNNing','NOscale'), fir1(10,.5,'noscale','Hanning','LOW')); %!assert(fir1(10,.5,'boxcar',[]), fir1(10,.5,'boxcar')); %% Test expected magnitudes of passbands, stopbands, and cutoff frequencies %!test %! b = fir1 (30, 0.3); %! h = abs (freqz (b, 1, [0, 0.3, 1], 2)); %! assert (h(1), 1, 1e-3) %! assert (all (h(2:3) <= [1/sqrt(2), 3e-3])) %!test %! b = fir1 (30, 0.7, "high"); %! h = abs (freqz (b, 1, [0, 0.7, 1], 2)); %! assert (h(3), 1, 1e-3) %! assert (all (h(1:2) <= [3e-3, 1/sqrt(2)])) %!test %! b = fir1 (30, [0.3, 0.7]); %! h = abs (freqz (b, 1, [0, 0.3, 0.5, 0.7, 1], 2)); %! assert (h(3), 1, 1e-3) %! assert (all (h([1:2, 4:5]) <= [3e-3, 1/sqrt(2), 1/sqrt(2), 3e-3])) %!test %! b = fir1 (50, [0.3, 0.7], "stop"); %! h = abs (freqz (b, 1, [0, 0.3, 0.5, 0.7, 1], 2)); %! assert (h(1), 1, 1e-3) %! assert (h(5), 1, 1e-3) %! assert (all (h(2:4) <= [1/sqrt(2), 3e-3, 1/sqrt(2)])) signal-1.4.5/inst/fir2.m0000644000000000000000000002162614456505401013174 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{b} =} fir2 (@var{n}, @var{f}, @var{m}) ## @deftypefnx {Function File} {@var{b} =} fir2 (@var{n}, @var{f}, @var{m}, @var{grid_n}) ## @deftypefnx {Function File} {@var{b} =} fir2 (@var{n}, @var{f}, @var{m}, @var{grid_n}, @var{ramp_n}) ## @deftypefnx {Function File} {@var{b} =} fir2 (@var{n}, @var{f}, @var{m}, @var{grid_n}, @var{ramp_n}, @var{window}) ## ## Produce an order @var{n} FIR filter with arbitrary frequency response ## @var{m} over frequency bands @var{f}, returning the @var{n}+1 filter ## coefficients in @var{b}. The vector @var{f} specifies the frequency band ## edges of the filter response and @var{m} specifies the magnitude response ## at each frequency. ## ## The vector @var{f} must be nondecreasing over the range [0,1], and the ## first and last elements must be 0 and 1, respectively. A discontinuous ## jump in the frequency response can be specified by duplicating a band edge ## in @var{f} with different values in @var{m}. ## ## The resolution over which the frequency response is evaluated can be ## controlled with the @var{grid_n} argument. The default is 512 or the ## next larger power of 2 greater than the filter length. ## ## The band transition width for discontinuities can be controlled with the ## @var{ramp_n} argument. The default is @var{grid_n}/25. Larger values ## will result in wider band transitions but better stopband rejection. ## ## An optional shaping @var{window} can be given as a vector with length ## @var{n}+1. If not specified, a Hamming window of length @var{n}+1 is used. ## ## To apply the filter, use the return vector @var{b} with the @code{filter} ## function, for example @code{y = filter (b, 1, x)}. ## ## Example: ## @example ## f = [0, 0.3, 0.3, 0.6, 0.6, 1]; m = [0, 0, 1, 1/2, 0, 0]; ## [h, w] = freqz (fir2 (100, f, m)); ## plot (f, m, ";target response;", w/pi, abs (h), ";filter response;"); ## @end example ## @seealso{filter, fir1} ## @end deftypefn function b = fir2(n, f, m, grid_n, ramp_n, window) if nargin < 3 || nargin > 6 print_usage; endif ## verify frequency and magnitude vectors are reasonable t = length(f); if t<2 || f(1)!=0 || f(t)!=1 || any(diff(f)<0) error ("fir2: frequency must be nondecreasing starting from 0 and ending at 1"); elseif t != length(m) error ("fir2: frequency and magnitude vectors must be the same length"); ## find the grid spacing and ramp width elseif (nargin>4 && length(grid_n)>1) || ... (nargin>5 && (length(grid_n)>1 || length(ramp_n)>1)) error ("fir2: grid_n and ramp_n must be integers"); endif if nargin < 4, grid_n=[]; endif if nargin < 5, ramp_n=[]; endif if (! (isscalar (n) && (n == fix (n)) && (n >= 0))) error ("fir2: n must be a non negative integer"); else # ensure n is used as a double type n = double(n); endif ## find the window parameter, or default to hamming w=[]; if length(grid_n)>1, w=grid_n; grid_n=[]; endif if length(ramp_n)>1, w=ramp_n; ramp_n=[]; endif if nargin < 6, window=w; endif if isempty(window), window=hamming(n+1); endif if !isreal(window) || ischar(window), window=feval(window, n+1); endif if length(window) != n+1, error ("fir2: window must be of length n+1"); endif ## Default grid size is 512... unless n+1 >= 1024 if isempty (grid_n) if n+1 < 1024 grid_n = 512; else grid_n = n+1; endif endif ## ML behavior appears to always round the grid size up to a power of 2 grid_n = 2 ^ nextpow2 (grid_n); ## Error out if the grid size is not big enough for the window if 2*grid_n < n+1 error ("fir2: grid size must be greater than half the filter order"); endif if isempty (ramp_n), ramp_n = fix (grid_n / 25); endif ## Apply ramps to discontinuities if (ramp_n > 0) ## remember original frequency points prior to applying ramps basef = f(:); basem = m(:); ## separate identical frequencies, but keep the midpoint idx = find (diff(f) == 0); f(idx) = f(idx) - ramp_n/grid_n/2; f(idx+1) = f(idx+1) + ramp_n/grid_n/2; f = [f(:);basef(idx)]'; ## make sure the grid points stay monotonic in [0,1] f(f<0) = 0; f(f>1) = 1; f = unique([f(:);basef(idx)(:)]'); ## preserve window shape even though f may have changed m = interp1(basef, basem, f); ## axis([-.1 1.1 -.1 1.1]) ## plot(f,m,'-xb;ramped;',basef,basem,'-or;original;'); pause; endif ## interpolate between grid points grid = interp1(f,m,linspace(0,1,grid_n+1)'); ## hold on; plot(linspace(0,1,grid_n+1),grid,'-+g;grid;'); hold off; pause; ## Transform frequency response into time response and ## center the response about n/2, truncating the excess if (rem(n,2) == 0) b = ifft([grid ; grid(grid_n:-1:2)]); mid = (n+1)/2; b = real ([ b([end-floor(mid)+1:end]) ; b(1:ceil(mid)) ]); else ## Add zeros to interpolate by 2, then pick the odd values below. b = ifft([grid ; zeros(grid_n*2,1) ;grid(grid_n:-1:2)]); b = 2 * real([ b([end-n+1:2:end]) ; b(2:2:(n+1))]); endif ## Multiplication in the time domain is convolution in frequency, ## so multiply by our window now to smooth the frequency response. ## Also, for matlab compatibility, we return return values in 1 row b = b(:)' .* window(:)'; endfunction %% Test that the grid size is rounded up to the next power of 2 %% FIXME: test fails randomly on i386 %!xtest %! f = [0 0.6 0.6 1]; m = [1 1 0 0]; %! b9 = fir2 (30, f, m, 9); %! b16 = fir2 (30, f, m, 16); %! b17 = fir2 (30, f, m, 17); %! b32 = fir2 (30, f, m, 32); %! assert ( isequal (b9, b16)) %! assert ( isequal (b17, b32)) %! assert (~isequal (b16, b17)) %% Test expected magnitudes of passbands, stopbands, and cutoff frequencies %!test %! f = [0, 0.7, 0.7, 1]; m = [0, 0, 1, 1]; %! b = fir2 (50, f, m); %! h = abs (freqz (b, 1, [0, 0.7, 1], 2)); %! assert (h(1) <= 3e-3) %! assert (h(2) <= 1/sqrt (2)) %! assert (h(3), 1, 2e-3) %!test %! f = [0, 0.25, 0.25, 0.75, 0.75, 1]; m = [0, 0, 1, 1, 0, 0]; %! b = fir2 (50, f, m); %! h = abs (freqz (b, 1, [0, 0.25, 0.5, 0.75, 1], 2)); %! assert (h(1) <= 3e-3) %! assert (h(2) <= 1/sqrt (2)) %! assert (h(3), 1, 2e-3) %! assert (h(4) <= 1/sqrt (2)) %! assert (h(5) <= 3e-3) %!test %! f = [0, 0.45, 0.45, 0.55, 0.55, 1]; m = [1, 1, 0, 0, 1, 1]; %! b = fir2 (50, f, m); %! h = abs (freqz (b, 1, [0, 0.45, 0.5, 0.55, 1], 2)); %! assert (h(1), 1, 2e-3) %! assert (h(2) <= 1/sqrt (2)) %! assert (h(3) <= 1e-1) %! assert (h(4) <= 1/sqrt (2)) %! assert (h(5), 1, 2e-3) %!test #bug 59066 %! f = [0, 0.45, 0.45, 0.55, 0.55, 1]; m = [1, 1, 0, 0, 1, 1]; %! b = fir2 (int32(50), f, m); %! assert(numel(b), 51) %! %! fail ("fir2 (50.1, f, m)", "fir2: n must be a non negative integer") %! fail ("fir2 (-1, f, m)", "fir2: n must be a non negative integer") %!demo %! f=[0, 0.3, 0.3, 0.6, 0.6, 1]; m=[0, 0, 1, 1/2, 0, 0]; %! [h, w] = freqz(fir2(100,f,m)); %! subplot(121); %! plot(f,m,';target response;',w/pi,abs(h),';filter response;'); %! subplot(122); %! plot(f,20*log10(m+1e-5),';target response (dB);',... %! w/pi,20*log10(abs(h)),';filter response (dB);'); %!demo %! f=[0, 0.3, 0.3, 0.6, 0.6, 1]; m=[0, 0, 1, 1/2, 0, 0]; %! plot(f,20*log10(m+1e-5),';target response;'); %! hold on; %! [h, w] = freqz(fir2(50,f,m,512,0)); %! plot(w/pi,20*log10(abs(h)),';filter response (ramp=0);'); %! [h, w] = freqz(fir2(50,f,m,512,25.6)); %! plot(w/pi,20*log10(abs(h)),';filter response (ramp=pi/20 rad);'); %! [h, w] = freqz(fir2(50,f,m,512,51.2)); %! plot(w/pi,20*log10(abs(h)),';filter response (ramp=pi/10 rad);'); %! hold off; %!demo %! % Classical Jakes spectrum %! % X represents the normalized frequency from 0 %! % to the maximum Doppler frequency %! asymptote = 2/3; %! X = linspace(0,asymptote-0.0001,200); %! Y = (1 - (X./asymptote).^2).^(-1/4); %! %! % The target frequency response is 0 after the asymptote %! X = [X, asymptote, 1]; %! Y = [Y, 0, 0]; %! %! plot(X,Y,'b;Target spectrum;'); %! hold on; %! [H,F]=freqz(fir2(20, X, Y)); %! plot(F/pi,abs(H),'c;Synthesized spectrum (n=20);'); %! [H,F]=freqz(fir2(50, X, Y)); %! plot(F/pi,abs(H),'r;Synthesized spectrum (n=50);'); %! [H,F]=freqz(fir2(200, X, Y)); %! plot(F/pi,abs(H),'g;Synthesized spectrum (n=200);'); %! hold off; %! title('Theoretical/Synthesized CLASS spectrum'); %! xlabel('Normalized frequency (Fs=2)'); %! ylabel('Magnitude'); signal-1.4.5/inst/firls.m0000644000000000000000000001052214456505401013442 0ustar0000000000000000## Copyright (C) 2006 Quentin Spencer ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{b} =} firls (@var{n}, @var{f}, @var{a}) ## @deftypefnx {Function File} {@var{b} =} firls (@var{n}, @var{f}, @var{a}, @var{w}) ## ## FIR filter design using least squares method. Returns a length @var{n}+1 ## linear phase filter such that the integral of the weighted mean ## squared error in the specified bands is minimized. ## ## The vector @var{f} specifies the frequencies of the band edges, normalized ## so that half the sample frequency is equal to 1. Each band is specified by ## two frequencies, to the vector must have an even length. ## ## The vector @var{a} specifies the amplitude of the desired response at each ## band edge. ## ## The optional argument @var{w} is a weighting function that contains one ## value for each band that weights the mean squared error in that band. ## ## @var{a} must be the same length as @var{f}, and @var{w} must be half the ## length of @var{f}. @var{n} must be even. If given an odd value, ## @code{firls} increments it by 1. ## ## The least squares optimization algorithm for computing FIR filter ## coefficients is derived in detail in: ## ## I. Selesnick, "Linear-Phase FIR Filter Design by Least Squares," ## http://cnx.org/content/m10577 ## @end deftypefn function coef = firls(N, frequencies, pass, weight, str); if (nargin < 3 || nargin > 6) print_usage; elseif (nargin == 3) weight = ones (1, length(pass)/2); str = []; elseif (nargin == 4) if ischar (weight) str = weight; weight = ones (size (pass)); else str = []; endif endif if length (frequencies) ~= length (pass) error("F and A must have equal lengths."); elseif 2 * length (weight) ~= length (pass) error("W must contain one weight per band."); elseif ischar (str) error("This feature is implemented yet"); else N += mod (N, 2); M = N/2; w = kron (weight(:), [-1; 1]); omega = frequencies * pi; i1 = 1:2:length (omega); i2 = 2:2:length (omega); ## Generate the matrix Q ## As illustrated in the above-cited reference, the matrix can be ## expressed as the sum of a Hankel and Toeplitz matrix. A factor of ## 1/2 has been dropped and the final filter coefficients multiplied ## by 2 to compensate. cos_ints = [omega; sin((1:N)' * omega)]; q = [1, 1./(1:N)]' .* (cos_ints * w); Q = toeplitz (q(1:M+1)) + hankel (q(1:M+1), q(M+1:end)); ## The vector b is derived from solving the integral: ## ## _ w ## / 2 ## b = / W(w) D(w) cos(kw) dw ## k / w ## - 1 ## ## Since we assume that W(w) is constant over each band (if not, the ## computation of Q above would be considerably more complex), but ## D(w) is allowed to be a linear function, in general the function ## W(w) D(w) is linear. The computations below are derived from the ## fact that: ## _ ## / a ax + b ## / (ax + b) cos(nx) dx = --- cos (nx) + ------ sin(nx) ## / 2 n ## - n ## cos_ints2 = [omega(i1).^2 - omega(i2).^2; ... cos((1:M)' * omega(i2)) - cos((1:M)' * omega(i1))] ./ ... ([2, 1:M]' * (omega(i2) - omega(i1))); d = [-weight .* pass(i1); weight .* pass(i2)] (:); b = [1, 1./(1:M)]' .* ((kron (cos_ints2, [1, 1]) + cos_ints(1:M+1,:)) * d); ## Having computed the components Q and b of the matrix equation, ## solve for the filter coefficients. a = Q \ b; coef = [ a(end:-1:2); 2 * a(1); a(2:end) ]; endif endfunction signal-1.4.5/inst/firpmord.m0000644000000000000000000003615614456505401014160 0ustar0000000000000000## Copyright (C) 2015 The Octave Project Developers ## ## See the file COPYRIGHT.md in the top-level directory of this ## distribution or . ## ## This file is part of Octave. ## ## Octave is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## Octave is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{n}, @var{Fout}, @var{a}, @var{w}] =} firpmord (@var{f}, @var{a}, @var{d}) ## @deftypefnx {Function File} {[@var{n}, @var{Fout}, @var{a}, @var{w}] =} firpmord (@var{f}, @var{a}, @var{d}, @var{fs}) ## @deftypefnx {Function File} {@var{c} =} firpmord (@var{f}, @var{a}, @var{d}, "cell") ## @deftypefnx {Function File} {@var{c} =} firpmord (@var{f}, @var{a}, @var{d}, @var{fs}, "cell") ## @cindex signal processing ## ## Estimate the filter-order needed for @code{firpm} to design a type-I or ## type-II linear-phase FIR filter according to the given specifications. ## ## @heading Arguments ## ## @table @var ## ## @item f ## A vector of real-numbers, increasing in the range (0, @var{fs}/2), giving the ## frequencies of the left and right edges of each band for which a specific ## amplitude response is desired (omitting 0 and @var{fs}/2, which are implied): ## [r1 l2 r2 @dots{}]. Transition-bands are defined implicitly as the regions ## between the given bands. ## ## @item a ## A vector of real-numbers giving the ideal amplitude response. An amplitude ## value is given for each band specified by @var{f}: [a1 a2 @dots{}]. 1 ## represents unity-gain, 0 represents infinite attenuation, and @minus{}1 ## represents a phase change of pi radians. ## ## @item d ## A vector of positive real-numbers giving the maximum allowable linear ## deviation from the amplitudes given in @var{a}, thus constraining the actual ## amplitude response (where defined by @var{f}) to be within @var{a} +/@minus{} ## @var{d}. Note that, though related, @var{d} does not equate to ## @code{firpm}'s @var{w} argument. ## ## @item fs ## ## The sampling-frequency, which defaults to 2. ## ## @end table ## ## @heading Usage ## ## The function returns the estimated filter-order, together with the other ## design specification values, in one of two forms suitable for use with ## @code{firpm}. By default, multiple return values are used; alternatively, by ## giving @qcode{"cell"} (or @qcode{"c"}) as the last argument to @code{firpmord}, ## the returned values are contained within a cell-array that can, if desired, ## be passed directly to @code{firpm}. ## ## The following examples illustrate the use of both mechanisms, as well as ## aspects of @code{firpmord} usage in general: ## ## @example ## @group ## # Low-pass; frequencies in kHz: ## [n f a w] = firpmord ([2.5 3], [1 0], [0.01 db2mag(-60)], 8); ## b = firpm (n, f, a, w); ## @end group ## @end example ## ## @example ## @group ## # Band-pass: ## c = firpmord ([3 4 8 9], [0 1 0], [1e-3 1e-2 1e-3], 20, "cell"); ## b = firpm (c@{:@}); ## @end group ## @end example ## ## @example ## @group ## # High-pass: ## b = firpm (firpmord ([6.4 8]/16, [0 1], [1e-4 0.01], "c")@{:@}); ## @end group ## @end example ## ## In cases where elements of @var{d} follow a repeating pattern (e.g.@: all the ## elements are equal, or elements corresponding to pass-bands are equal and ## elements corresponding to stop-bands are equal), only as many elements as are ## needed to establish the pattern need be given. ## ## For example, the following @code{firpmord} invocation pairs are equivalent: ## ## @example ## @group ## # Low-pass: ## firpmord ([0.4 0.5], [0 1], [db2mag(-72) db2mag(-72)]); ## firpmord ([0.4 0.5], [0 1], [db2mag(-72)]); ## @end group ## @end example ## ## @example ## @group ## # Multi-band-pass: ## ds = db2mag(-80); dp = 0.01; ## firpmord ([1 2 3 4 5 6 7 8]/10, [0 1 0 1 0], [ds dp ds dp ds]); ## firpmord ([1 2 3 4 5 6 7 8]/10, [0 1 0 1 0], [ds dp]); ## @end group ## @end example ## ## @heading Notes ## ## The estimation algorithm used is per Ichige et al.@footnote{ K. Ichige, M. ## Iwaki, algorithm and R. Ishii, `Accurate Estimation of Minimum Filter Length ## for Optimum FIR Digital Filters', IEEE Transactions on Circuits and Systems, ## Vol.@: 47, No.@: 10, 2000, pp.@: 1008--1017} Accuracy tends to decrease as ## the number of bands increases. Even with two bands (i.e.@: high-pass or ## low-pass), the algorithm may under- or over-estimate. See the ## @code{firpmord} demonstrations for some examples. ## ## In order to precisely determine the minimum order needed for a particular ## design, @code{firpmord} could be used to seed an algorithm iterating ## invocations of @code{firpm} (as exemplified in demonstration number five). ## ## @heading Related documentation ## ## @seealso{firpm, kaiserord} ## ## @end deftypefn function [N, Fout, A, W] = firpmord (F, A, D, Fs = 2, cell) len = @(x) length (x); cell_given = nargin > 4; if (ischar (Fs) && nargin == 4) cell = Fs; Fs = 2; cell_given = 1; endif return_as_cell = ischar (cell) && strncmpi (cell, "cell", numel (cell)); Fs = real (Fs); if nargin < 3 || nargin > 5 || (!return_as_cell && cell_given) print_usage; elseif (! (isscalar (Fs) && Fs > 0)) error ("firpmord parameter Fs (sampling-frequency) must be a positive \ number"); endif F = real (F(:)) / Fs; A = real (A(:)); D = real (D(:)); if (any (F <= 0) || any (F >= .5) || any ([F; 1] - [0; F] <= 0)) error ("firpmord parameter F (band-edge frequencies) elements must \ increase between 0 and Fs/2") elseif (len (F) == 0 || len (F) != 2 * len (A) - 2) error ("firpmord parameter F (band-edge frequencies) length must be twice \ the length of A, less 2") elseif (len (D) < 1 || len (D) > len (A) || any (D <= 0)) error ("firpmord parameter D (deviations) must be a vector of positive \ numbers, its length not exceeding that of A") endif ## The following step could also be done for D, but the concision gain ## is not as compelling, and would result in the loss of the useful ## cross-check between the lengths of F and D. ## ## Repeat (as necessary) elements of A to obtain 1 element/band: l=1; for k=len (D)+1:len (A) D(k,1) = D(l++); endfor ## Scale D w.r.t. A: D ./= abs (A) + (A==0); ## Find the longest length needed to implement any of the ## low-pass or high-pass transitions within the given edges. ## HP transitions are mirrored in [0,.5] then treated as LP: Fl = F(1:2:(len (F) - 1)); # Freqs at left of transition. Fr = F(2:2:(len (F) - 0)); # Freqs at right of transition. L = 2; # Anything less is not a filter. for k=1:len (Fl) # (Fl, Fr have equal length.) if (A(k) > A(k+1)) # Low-pass transition? L = max (L, estimate_lp (Fl(k), Fr(k), D(k), D(k+1))); elseif (A(k) < A(k+1)) # High-pass transition? L = max (L, estimate_lp (.5-Fr(k), .5-Fl(k), D(k+1), D(k))); endif endfor ## Format length & specs for firpm: Fout = [0; F*2; 1]; W = max (D) ./ D; N = ceil (L) - 1; # Filter order. N += A(end) != 0 && rem (N, 2); # Fix-up high-pass/band-stop. A = kron(A, [1;1]); if (nargout < 2 && return_as_cell) N = {N, Fout, A, W}; endif endfunction ## Estimate filter-length needed for LP transition (Ichige, 2000): function L = estimate_lp (fp, fs, dp, ds) dF = fs-fp; assert (dF > 0) # Ichige eqn.# v = @(d) 2.325 * (-log10 (d))^-.445 * dF^-1.39; # (10) g = @(fp,d) 2/pi * atan (v(d) * (1/fp - 1/(.5-dF))); # (9) h = @(fp,c) 2/pi * atan (c/dF * (1/fp - 1/(.5-dF))); # (15) Nc = ceil (1.101 * (-log10 (2*dp))^1.1 / dF + 1); # (8) ... N3 = ceil (Nc * (g(fp, dp) + g(.5-fs, dp) + 1)/3); # (11) Nm = .52 * log10 (dp/ds) / dF * (-log10 (dp))^.17; # (15) DN = ceil (Nm * (h(fp, 1.1) - (h(.5-fs, .29) - 1)/2)); # (15) L = N3 + DN; # (15) endfunction ## Invocation tests: %!error firpmord ([1 2], [1 0], [1 1], [1 1]); %!error firpmord ([0 2], [1 0], [1 1]); %!error firpmord ([.1 1], [1 0], [1 1]); %!error firpmord ([.1 .9], [1], [.1 .1]); %!error firpmord ([.1 .2], [1 0], [.1 .1 .1]); %!error firpmord ([.1 .2], [1 0], [1 0]); %!assert ( %! firpmord ([0.4 0.5], [0 1], [2.5e-4 2.5e-4]), %! firpmord ([0.4 0.5], [0 1], [2.5e-4])) %!test ds = 1e-4; dp = 0.01; assert ( %! firpmord ([1 2 3 4 5 6 7 8]/10, [0 1 0 1 0], [ds dp ds dp ds]), %! firpmord ([1 2 3 4 5 6 7 8]/10, [0 1 0 1 0], [ds dp])) ## Tests using examples from the Ichige paper, tables II & III. ## There are some slight discrepancies; the reason is unknown: %!assert (1 + firpmord ([.1 .2], [0 1], [1e-4 .01], 1), 33) %!assert (1 + firpmord ([ 15 20], [ 1 0], [ .1 .001], 100), 38) %!assert (1 + firpmord ([ 8 10 ], [0 1 ], [.001 .1 ], 100), 91) %!assert (1 + firpmord ([ 8 10 15 20], [0 1 0], [.001 .1 .001], 100), 90) #+1? %!assert (1 + firpmord ([17 20 ], [1 0 ], [.01 1e-4 ], 100), 107)#-1? %!assert (1 + firpmord ([ 22 25], [ 0 1], [ 1e-4 .01], 100), 107) %!assert (1 + firpmord ([17 20 22 25], [1 0 1], [.01 1e-4 .01], 100), 107) %!assert (1 + firpmord ([ 21 25], [ 1 0], [ .01 1e-4], 100), 81) #+1? %!assert (1 + firpmord ([10 20 ], [0 1 ], [1e-4 .01 ], 100), 33) %!assert (1 + firpmord ([10 20 21 25], [0 1 0], [1e-4 .01 1e-4], 100), 81) #+1? %!assert (1 + firpmord ([20 25 ], [1 0 ], [.01 1e-4 ], 100), 65) #+1? %!assert (1 + firpmord ([ 26 30], [ 0 1], [ 1e-4 .01], 100), 81) #+2? %!assert (1 + firpmord ([20 25 26 30], [1 0 1], [.01 1e-4 .01], 100), 81) #+2? ## Demonstrations: %! %!demo %! %! db2mag = @(x) 10^(x/20); %! %! fs = 8000; %! [n f a w] = firpmord ([2500 3000], [1 0], [0.01 db2mag(-60)], fs); %! b = firpm (n, f, a, w); %! %! [h f] = freqz (b, 1, 2^14); clf %! plot (fs/2*f/pi, 20*log10 (abs (h))); grid on; axis ([0 fs/2 -90 5]) %! ylabel ("Magnitude (dB)"); xlabel ("Frequency (Hz)") %! title (sprintf ("Response analysis of firpmord / firpm low-pass filter design (order=%i)", length (b) - 1)) %! axes ("position", [.24 .4 .4 .3]) %! plot (fs/2*f/pi, abs (h)); grid on; axis ([0 2600 x=.987 2-x]) %! ylabel ("Magnitude") %! title ("Pass-band detail") %! %-------------------------------------------------- %! % Figure shows analysis of filter designed using %! % firpm with firpmord; specs. are almost met. %! %!demo %! %! db2mag = @(x) 10^(x/20); %! %! b = firpm (firpmord ([0.3 0.4], [0 1], [db2mag(-80) .01], "c"){:}); %! %! [h f] = freqz (b, 1, 2^14); clf %! plot (f/pi, 20*log10 (abs (h))); grid on; axis ([0 1 -110 5]) %! ylabel ("Magnitude (dB)"); xlabel ("Frequency (normalized)") %! title (sprintf ("Response analysis of firpmord / firpm high-pass filter design (order=%i)", length (b) - 1)) %! axes ("position", [.52 .4 .35 .3]) %! plot (f/pi, abs (h)); grid on; axis ([.39 1 x=.987 2-x]) %! ylabel ("Magnitude") %! title ("Pass-band detail") %! %-------------------------------------------------- %! % Figure shows analysis of filter designed using %! % firpm with firpmord; specs. are exceeded. %! %!demo %! %! db2mag = @(x) 10^(x/20); %! %! ds = db2mag (-80); dp = 0.01; %! b = firpm (firpmord ([1 2 3 4 5 6 7 8]/10, [0 1 0 1 0], [ds dp], "c"){:}); %! %! [h f] = freqz (b, 1, 2^14); clf %! plot (f/pi, 20*log10 (abs (h))); grid on; axis ([0 1 -110 5]) %! ylabel ("Magnitude (dB)"); xlabel ("Frequency (normalized)") %! title ("Response analysis of firpmord / firpm multi-band-pass filter design") %! title (sprintf ("Response analysis of firpmord / firpm multi-band-pass filter design (order=%i)", length (b) - 1)) %! axes ("position", [.38 .5 .5 .2]) %! plot (f/pi, abs (h)); grid on; axis ([.11 .79 x=.986 2-x]) %! ylabel ("Magnitude") %! title ("Pass-bands detail") %! %-------------------------------------------------- %! % Figure shows analysis of filter designed using %! % firpm with firpmord; specs. are met. %! %!demo %! %! db2mag = @(x) 10^(x/20); %! %! ds = db2mag (-40); dp = 1 - db2mag (-0.1); %! b = firpm (firpmord ([2 3 8 9]/32, [0 1 0], [ds dp], "c"){:}); %! %! [h f] = freqz (b, 1, 2^14); clf %! plot (f/pi, 20*log10 (abs (h))); grid on; axis ([0 1 -50 3]) %! ylabel ("Magnitude (dB)"); xlabel ("Frequency (normalized)") %! title (sprintf ("Response analysis of firpmord / firpm band-pass filter design (order=%i)", length (b) - 1)) %! axes ("position", [.45 .5 .4 .3]) %! plot (f/pi, 20*log10 (abs (h))); grid on; axis ([.08 .26 x=-.13 -x]) %! ylabel ("Magnitude (dB)") %! title ("Pass-band detail") %! %-------------------------------------------------- %! % Figure shows analysis of filter designed using %! % firpm with firpmord; specs. are not met. %! %!demo %! %! % FIRPMX: F, A, D, Fs are as firpmord. %! % type in {0,1,2} constrains order to be {even,odd,either} resp. %! %! function h = firpmx (type, F, A, D, Fs = 2) %! type *= !A(end); step = 2; bounds = [0 0]; %! while (bounds(2) - bounds(1) != step) %! if all (!bounds) [n f a w] = firpmord (F, A, D, Fs); %! elseif (!bounds(1)) n = min (n - step, round (n * 0.994)); %! elseif (!bounds(2)) n = max (n + step, round (n / 0.998)); %! else n = fix (mean (bounds)); %! endif %! n += rem (n + rem (type, 2), step); %! [b m] = firpm (n, f, a, w); %! bounds(1 + (met = (abs(m) <= max (D)))) = n; %! step -= bounds(2) - bounds(1) == type; %! if (met) h = b; endif %! endwhile %! endfunction %! %! db2mag = @(x) 10^(x/20); %! %! ds = db2mag (-40); dp = 1 - db2mag (-0.1); %! b = firpmx (2, [2 3 8 9]/32, [0 1 0], [ds dp]); %! %! [h f] = freqz (b, 1, 2^14); clf %! plot (f/pi, 20*log10 (abs (h))); grid on; axis ([0 1 -50 3]) %! ylabel ("Magnitude (dB)"); xlabel ("Frequency (normalized)") %! title (sprintf ("Response analysis of firpmord / iterative-firpm band-pass filter design (order=%i)", length (b) - 1)) %! axes ("position", [.45 .5 .4 .3]) %! plot (f/pi, 20*log10 (abs (h))); grid on; axis ([.08 .26 x=-.13 -x]) %! ylabel ("Magnitude (dB)") %! title ("Pass-band detail") %! %-------------------------------------------------- %! % Figure shows analysis of filter designed iteratively %! % using firpm with firpmord, so that specs. are met. signal-1.4.5/inst/flattopwin.m0000644000000000000000000000445414456505401014521 0ustar0000000000000000## Author: Paul Kienzle (2004) ## This program is granted to the public domain. ## -*- texinfo -*- ## @deftypefn {Function File} {} flattopwin (@var{m}) ## @deftypefnx {Function File} {} flattopwin (@var{m}, "periodic") ## @deftypefnx {Function File} {} flattopwin (@var{m}, "symmetric") ## ## Return the filter coefficients of a Flat Top window of length @var{m}. ## The Flat Top window is defined by the function f(w): ## ## @example ## @group ## f(w) = 1 - 1.93 cos(2 pi w) + 1.29 cos(4 pi w) ## - 0.388 cos(6 pi w) + 0.0322cos(8 pi w) ## @end group ## @end example ## ## where w = i/(m-1) for i=0:m-1 for a symmetric window, or ## w = i/m for i=0:m-1 for a periodic window. The default ## is symmetric. The returned window is normalized to a peak ## of 1 at w = 0.5. ## ## This window has low pass-band ripple, but high bandwidth. ## ## According to [1]: ## ## The main use for the Flat Top window is for calibration, due ## to its negligible amplitude errors. ## ## [1] Gade, S; Herlufsen, H; (1987) "Use of weighting functions in DFT/FFT ## analysis (Part I)", Bruel & Kjaer Technical Review No.3. ## @end deftypefn function w = flattopwin (m, opt) if (nargin < 1 || nargin > 2) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("flattopwin: M must be a positive integer"); endif N = m - 1; if (nargin == 2) switch (opt) case "periodic" N = m; case "symmetric" N = m - 1; otherwise error ("flattopwin: window type must be either \"periodic\" or \"symmetric\""); endswitch endif if (m == 1) w = 1; else x = 2*pi*[0:m-1]'/N; w = (1-1.93*cos(x)+1.29*cos(2*x)-0.388*cos(3*x)+0.0322*cos(4*x))/4.6402; endif endfunction %!assert (flattopwin (1), 1); %!assert (flattopwin (2), 0.0042 / 4.6402 * ones (2, 1), eps); %!assert (flattopwin (15), flipud (flattopwin (15)), 10*eps); %!assert (flattopwin (16), flipud (flattopwin (16)), 10*eps); %!assert (flattopwin (15), flattopwin (15, "symmetric")); %!assert (flattopwin (16)(1:15), flattopwin (15, "periodic")); %% Test input validation %!error flattopwin () %!error flattopwin (0.5) %!error flattopwin (-1) %!error flattopwin (ones (1, 4)) %!error flattopwin (1, 2) %!error flattopwin (1, 2, 3) %!error flattopwin (1, "invalid") signal-1.4.5/inst/fracshift.m0000644000000000000000000001414514456505401014301 0ustar0000000000000000## Copyright (C) 2008 Eric Chassande-Mottin, CNRS (France) ## Copyright (C) 2018 Juan Pablo Carbajal ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## Author: Eric Chassande-Mottin, CNRS (France) ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{y}, @var{h}] =} fracshift (@var{x}, @var{d}) ## @deftypefnx {Function File} {@var{y} =} fracshift (@var{x}, @var{d}, @var{h}) ## Shift the series @var{x} by a (possibly fractional) number of samples @var{d}. ## The interpolator @var{h} is either specified or either designed with a ## Kaiser-windowed sinecard. ## @seealso{circshift} ## @end deftypefn ## Ref [1] A. V. Oppenheim, R. W. Schafer and J. R. Buck, ## Discrete-time signal processing, Signal processing series, ## Prentice-Hall, 1999 ## ## Ref [2] T.I. Laakso, V. Valimaki, M. Karjalainen and U.K. Laine ## Splitting the unit delay, IEEE Signal Processing Magazine, ## vol. 13, no. 1, pp 30--59 Jan 1996 function [y, h] = fracshift( x, d, h = []) if (nargin > 3 || nargin < 2) print_usage; endif; ## check if filter is a vector if ~isempty (h) && ~isvector (h) error ('Octave:invalid-input-arg', ... 'fracshift.m: the filter h should be a vector'); endif ## check if input is a row vector isrowvector = false; if ((rows (x) == 1) && (columns (x) > 1)) x = x(:); isrowvector = true; endif ## if the delay is an exact integer, use circshift if d == fix (d) if ~isempty (h) warning ('Octave:ignore-input-arg', ... ['Provided filter is not used if shift is an integer.\n' ... 'Consider using circshift instead.\n']); endif else ## if required, filter design using reference [1] if isempty (h) h = design_filter (d); endif Lx = length (x); Lh = length (h); L = ( Lh - 1 ) / 2.0; Ly = Lx; ## pre and postpad filter response hpad = prepad (h, Lh); offset = floor (L); hpad = postpad (hpad, Ly + offset); ## filtering xfilt = upfirdn (x, hpad, 1, 1); x = xfilt((offset + 1):(offset + Ly), :); endif y = circshift (x, fix (d)); if isrowvector, y = y.'; endif endfunction function h = design_filter (d) ## properties of the interpolation filter log10_rejection = -3.0; ## use empirical formula from [1] Chap 7, Eq. (7.63) p 476 rejection_dB = -20.0 * log10_rejection; ## determine parameter of Kaiser window ## use empirical formula from [1] Chap 7, Eq. (7.62) p 474 ## FIXME since the parameters are fix the conditional below is not needed if ((rejection_dB >= 21) && (rejection_dB <= 50)) beta = 0.5842 * (rejection_dB - 21.0) ^ 0.4 + ... 0.07886 * (rejection_dB - 21.0); elseif (rejection_dB > 50) beta = 0.1102 * (rejection_dB - 8.7); else beta = 0.0; endif ## properties of the interpolation filter stopband_cutoff_f = 0.5; roll_off_width = stopband_cutoff_f / 10; ## ideal sinc filter ## determine filter length L = ceil ((rejection_dB - 8.0) / (28.714 * roll_off_width)); t = (-L:L).'; ideal_filter = 2 * stopband_cutoff_f * ... sinc (2 * stopband_cutoff_f * (t - (d - fix (d)))); ## apodize ideal (sincard) filter response m = 2 * L; t = (0:m).' - (d - fix (d)); t = 2 * beta / m * sqrt (t .* (m - t)); w = besseli (0, t) / besseli (0, beta); h = w .* ideal_filter; endfunction %!test %! d = [1.5 7/6]; %! N = 1024; %! t = ((0:N-1)-N/2).'; %! tt = bsxfun (@minus, t, d); %! err1= err2 = zeros(N/2,1); %! for n = 0:N/2-1, %! phi0 = 2*pi*rand; %! f0 = n/N; %! sigma = N/4; %! x = exp(-t.^2/(2*sigma)).*sin(2*pi*f0*t + phi0); %! xx = exp(-tt.^2/(2*sigma)).*sin(2*pi*f0*tt + phi0); %! [y,h] = fracshift(x, d(1)); %! err1(n+1) = max (abs (y - xx(:,1))); %! [y,h] = fracshift(x, d(2)); %! err2(n+1) = max (abs (y - xx(:,2))); %! endfor %! rolloff = .1; %! rejection = 10^-3; %! idx_inband = 1:ceil((1-rolloff)*N/2)-1; %! assert (max (err1(idx_inband)) < rejection); %! assert (max (err2(idx_inband)) < rejection); %!test %! N = 1024; %! p = 6; %! q = 7; %! d1 = 64; %! d2 = d1*p/q; %! t = 128; %! %! [b a] = butter (10,.25); %! n = zeros (N, 1); %! n(N/2+(-t:t)) = randn(2*t+1,1); %! n = filter(b,a,n); %! n1 = fracshift(n,d1); %! n1 = resample(n1,p,q); %! n2 = resample(n,p,q); %! n2 = fracshift(n2,d2); %! err = abs (n2 - n1); %! rejection = 10^-3; %! assert(max (err) < rejection); %!test #integer shift similar similar to non-integer %! N = 1024; %! t = linspace(0, 1, N).'; %! x = exp(-t.^2/2/0.25^2).*sin(2*pi*10*t); %! d = 10; %! y = fracshift(x, d); %! yh = fracshift(x, d+1e-8); %! assert(y, yh, 1e-8) %!warning fracshift([1 2 3 2 1], 3, h=0.5); #integer shift and filter provided %!test #bug 52758 %! x = [0 1 0 0 0 0 0 0]; %! y = fracshift(x, 1); %! assert (size(x) == size(y)) %!test #bug 47387 %! N = 1024; %! t = linspace(0, 1, N).'; %! x = exp(-t.^2/2/0.25^2).*sin(2*pi*10*t); %! dt = 0.25; %! d = dt / (t(2) - t(1)); %! y = fracshift(x, d); %! L = 37; %! _t = (-L:L).'; %! ideal_filter = sinc (_t - (d - fix (d))); %! m = 2 * L; %! _t = (0:m).' - (d - fix (d)); %! beta = 5.6533; %! _t = 2 * beta / m * sqrt (_t .* (m - _t)); %! w = besseli (0, _t) / besseli (0, beta); %! h = w .* ideal_filter; %! yh = fracshift(x, d, h); %! assert(y, yh, 1e-8) %!demo %! N = 1024; %! t = linspace (0, 1, N).'; %! x = exp(-t.^2/2/0.25^2).*sin(2*pi*10*t); %! %! dt = 0.25; %! d = dt / (t(2) - t(1)); %! y = fracshift(x, d); %! %! plot(t,y,'r-;shifted;', t, x, 'k-;original;') %! axis tight %! xlabel ('time') %! ylabel ('signal') signal-1.4.5/inst/freqs.m0000644000000000000000000000273414456505401013451 0ustar0000000000000000## Copyright (C) 2003 Julius O. Smith III ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{h} =} freqs (@var{b}, @var{a}, @var{w}) ## @deftypefnx {Function File} {} freqs (@var{b}, @var{a}, @var{w}) ## ## Compute the s-plane frequency response of the IIR filter B(s)/A(s) as ## H = polyval(B,j*W)./polyval(A,j*W). If called with no output ## argument, a plot of magnitude and phase are displayed. ## ## Example: ## @example ## b = [1 2]; a = [1 1]; ## w = linspace (0, 4, 128); ## freqs (b, a, w); ## @end example ## @end deftypefn function H = freqs(B,A,W) if (nargin ~= 3 || nargout>1) print_usage; endif H = polyval(B,j*W)./polyval(A,j*W); if nargout<1 freqs_plot(W,H); endif endfunction %!demo %! B = [1 2]; %! A = [1 1]; %! w = linspace(0,4,128); %! freqs(B,A,w); signal-1.4.5/inst/freqs_plot.m0000644000000000000000000000276214456505401014510 0ustar0000000000000000## Copyright (C) 2003 Julius O. Smith III ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} freqs_plot (@var{w}, @var{h}) ## Plot the amplitude and phase of the vector @var{h}. ## @end deftypefn function freqs_plot(w,h) n = length(w); mag = 20*log10(abs(h)); phase = unwrap(arg(h)); maxmag = max(mag); subplot(211); plot(w, mag, ";Magnitude (dB);"); title('Frequency response plot by freqs'); axis("labely"); ylabel("dB"); xlabel(""); grid("on"); if (maxmag - min(mag) > 100) # make 100 a parameter? axis([w(1), w(n), maxmag-100, maxmag]); else axis("autoy"); endif subplot(212); plot(w, phase/(2*pi), ";Phase (radians/2pi);"); axis("label"); title(""); grid("on"); axis("autoy"); xlabel("Frequency (rad/sec)"); ylabel("Cycles"); axis([w(1), w(n)]); endfunction signal-1.4.5/inst/fwhm.m0000644000000000000000000001277614456505401013301 0ustar0000000000000000## Author: Petr Mikulik (2009) ## This program is granted to the public domain. ## -*- texinfo -*- ## @deftypefn {Function File} {@var{f} =} fwhm (@var{y}) ## @deftypefnx {Function File} {@var{f} =} fwhm (@var{x}, @var{y}) ## @deftypefnx {Function File} {@var{f} =} fwhm (@dots{}, "zero") ## @deftypefnx {Function File} {@var{f} =} fwhm (@dots{}, "min") ## @deftypefnx {Function File} {@var{f} =} fwhm (@dots{}, "alevel", @var{level}) ## @deftypefnx {Function File} {@var{f} =} fwhm (@dots{}, "rlevel", @var{level}) ## ## Compute peak full-width at half maximum (FWHM) or at another level of peak ## maximum for vector or matrix data @var{y}, optionally sampled as @math{y(x)}. ## If @var{y} is a matrix, return FWHM for each column as a row vector. ## ## The default option "zero" computes fwhm at half maximum, i.e. ## @math{0.5*max(y)}. The option "min" computes fwhm at the middle curve, i.e. ## @math{0.5*(min(y)+max(y))}. ## ## The option "rlevel" computes full-width at the given relative level of peak ## profile, i.e. at @math{rlevel*max(y)} or @math{rlevel*(min(y)+max(y))}, ## respectively. For example, @code{fwhm (@dots{}, "rlevel", 0.1)} computes ## full width at 10 % of peak maximum with respect to zero or minimum; FWHM is ## equivalent to @code{fwhm(@dots{}, "rlevel", 0.5)}. ## ## The option "alevel" computes full-width at the given absolute level of ## @var{y}. ## ## Return 0 if FWHM does not exist (e.g. monotonous function or the function ## does not cut horizontal line at @math{rlevel*max(y)} or ## @math{rlevel*(max(y)+min(y))} or alevel, respectively). ## ## @end deftypefn function myfwhm = fwhm (y, varargin) if nargin < 1 || nargin > 5 print_usage; endif opt = 'zero'; is_alevel = 0; level = 0.5; if nargin==1 x = 1:length(y); else if ischar(varargin{1}) x = 1:length(y); k = 1; else x = y; y = varargin{1}; k = 2; endif while k <= length(varargin) if strcmp(varargin{k}, 'alevel') is_alevel = 1; k = k+1; if k > length(varargin) error('option "alevel" requires an argument'); endif level = varargin{k}; if ~isreal(level) || length(level) > 1 error('argument of "alevel" must be real number'); endif k = k+1; break endif if any(strcmp(varargin{k}, {'zero', 'min'})) opt = varargin{k}; k = k+1; endif if k > length(varargin) break; endif if strcmp(varargin{k}, 'rlevel') k = k+1; if k > length(varargin) error('option "rlevel" requires an argument'); endif level = varargin{k}; if ~isreal(level) || length(level) > 1 || level(1) < 0 || level(:) > 1 error('argument of "rlevel" must be real number from 0 to 1 (it is 0.5 for fwhm)'); endif k = k+1; break endif break endwhile if k ~= length(varargin)+1 error('fwhm: extraneous option(s)'); endif endif ## test the y matrix [nr, nc] = size(y); if (nr == 1 && nc > 1) y = y'; nr = nc; nc = 1; endif if length(x) ~= nr error('dimension of input arguments do not match'); endif ## Shift matrix columns so that y(+-xfwhm) = 0: if is_alevel ## case: full-width at the given absolute position y = y - level; else if strcmp(opt, 'zero') ## case: full-width at half maximum y = y - level * repmat(max(y), nr, 1); else ## case: full-width above background y = y - level * repmat((max(y) + min(y)), nr, 1); endif endif ## Trial for a "vectorizing" calculation of fwhm (i.e. all ## columns in one shot): ## myfwhm = zeros(1,nc); # default: 0 for fwhm undefined ## ind = find (y(1:end-1, :) .* y(2:end, :) <= 0); ## [r1,c1] = ind2sub(size(y), ind); ## ... difficult to proceed further. ## Thus calculate fwhm for each column independently: myfwhm = zeros(1,nc); # default: 0 for fwhm undefined for n=1:nc yy = y(:, n); ind = find((yy(1:end-1) .* yy(2:end)) <= 0); if length(ind) >= 2 && yy(ind(1)) > 0 # must start ascending ind = ind(2:end); endif [mx, imax] = max(yy); # protection against constant or (almost) monotonous functions if length(ind) >= 2 && imax >= ind(1) && imax <= ind(end) ind1 = ind(1); ind2 = ind1 + 1; xx1 = x(ind1) - yy(ind1) * (x(ind2) - x(ind1)) / (yy(ind2) - yy(ind1)); ind1 = ind(end); ind2 = ind1 + 1; xx2 = x(ind1) - yy(ind1) * (x(ind2) - x(ind1)) / (yy(ind2) - yy(ind1)); myfwhm(n) = xx2 - xx1; endif endfor endfunction %!test %! x=-pi:0.001:pi; y=cos(x); %! assert( abs(fwhm(x, y) - 2*pi/3) < 0.01 ); %! %!test %! assert( fwhm(-10:10) == 0 && fwhm(ones(1,50)) == 0 ); %! %!test %! x=-20:1:20; %! y1=-4+zeros(size(x)); y1(4:10)=8; %! y2=-2+zeros(size(x)); y2(4:11)=2; %! y3= 2+zeros(size(x)); y3(5:13)=10; %! assert( max(abs(fwhm(x, [y1;y2;y3]') - [20.0/3,7.5,9.25])) < 0.01 ); %! %!test %! x=1:3; y=[-1,3,-1]; assert(abs(fwhm(x,y)-0.75)<0.001 && abs(fwhm(x,y,'zero')-0.75)<0.001 && abs(fwhm(x,y,'min')-1.0)<0.001); %! %!test %! x=1:3; y=[-1,3,-1]; assert(abs(fwhm(x,y, 'rlevel', 0.1)-1.35)<0.001 && abs(fwhm(x,y,'zero', 'rlevel', 0.1)-1.35)<0.001 && abs(fwhm(x,y,'min', 'rlevel', 0.1)-1.40)<0.001); %! %!test %! x=1:3; y=[-1,3,-1]; assert(abs(fwhm(x,y, 'alevel', 2.5)-0.25)<0.001 && abs(fwhm(x,y,'alevel', -0.5)-1.75)<0.001); %! %!test %! x=-10:10; assert( fwhm(x.*x) == 0 ); %! %!test %! x=-5:5; y=18-x.*x; assert( abs(fwhm(y)-6.0) < 0.001 && abs(fwhm(x,y,'zero')-6.0) < 0.001 && abs(fwhm(x,y,'min')-7.0 ) < 0.001); signal-1.4.5/inst/fwht.m0000644000000000000000000000542314456505401013277 0ustar0000000000000000## Copyright (C) 2013-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} fwht (@var{x}) ## @deftypefnx {Function File} {} fwht (@var{x}, @var{n}) ## @deftypefnx {Function File} {} fwht (@var{x}, @var{n}, @var{order}) ## Compute the Walsh-Hadamard transform of @var{x} using the Fast ## Walsh-Hadamard Transform (FWHT) algorithm. If the input is a matrix, ## the FWHT is calculated along the columns of @var{x}. ## ## The number of elements of @var{x} must be a power of 2; if not, the ## input will be extended and filled with zeros. If a second argument ## is given, the input is truncated or extended to have length @var{n}. ## ## The third argument specifies the @var{order} in which the returned ## Walsh-Hadamard transform coefficients should be arranged. The ## @var{order} may be any of the following strings: ## ## @table @asis ## @item "sequency" ## The coefficients are returned in sequency order. This is the default ## if @var{order} is not given. ## ## @item "hadamard" ## The coefficients are returned in Hadamard order. ## ## @item "dyadic" ## The coefficients are returned in Gray code order. ## @end table ## ## @seealso{ifwht} ## @end deftypefn function y = fwht (x, n, order) if (nargin < 1 || nargin > 3) print_usage (); elseif (nargin == 1) n = order = []; elseif (nargin == 2) order = []; endif [y, n] = __fwht_opts__ ("fwht", x, n, order); y /= n; endfunction %!assert (isempty (fwht ([]))); %!assert (fwht (zeros (16)), zeros (16)); %!assert (fwht (ones (16, 1)), [1; (zeros (15, 1))]); %!assert (fwht (zeros (17, 1)), zeros (32, 1)); %!assert (fwht ([1 -1 1 -1 1 -1 1 -1]), [0 0 0 0 0 0 0 1]); %!test %! x = randi (16, 16); %! assert (ifwht (fwht (x)), x); %!test %! x = randi (16, 16); %! assert (ifwht (fwht (x, [], "sequency"), [], "sequency"), x); %!test %! x = randi (16, 16); %! assert (ifwht (fwht (x, [], "hadamard"), [], "hadamard"), x); %!test %! x = randi (16, 16); %! assert (ifwht (fwht (x, [], "dyadic"), [], "dyadic"), x); %% Test input validation %!error fwht (); %!error fwht (1, 2, 3, 4); %!error fwht (0, 0); %!error fwht (0, 5); %!error fwht (0, [], "invalid"); signal-1.4.5/inst/gauspuls.m0000644000000000000000000000430414456505401014167 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## Copyright (C) 2018-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} gauspuls (@var{t}) ## @deftypefnx {Function File} {@var{y} =} gauspuls (@var{t}, @var{fc}) ## @deftypefnx {Function File} {@var{y} =} gauspuls (@var{t}, @var{fc}, @var{bw}) ## Generate a Gaussian modulated sinusoidal pulse sampled at times @var{t}. ## @seealso{pulstran, rectpuls, tripuls} ## @end deftypefn function y = gauspuls (t, fc = 1e3, bw = 0.5) if (nargin < 1 || nargin > 3) print_usage (); endif if (! isreal (fc) || ! isscalar (fc) || fc < 0) error ("gauspuls: FC must be a non-negative real scalar") endif if (! isreal (bw) || ! isscalar (bw) || bw <= 0) error ("gauspuls: BW must be a positive real scalar") endif fv = -(bw^2 * fc^2) / (8 * log (10 ^ (-6/20))); tv = 1 / (4*pi^2 * fv); y = exp (-t .* t / (2*tv)) .* cos (2*pi*fc * t); endfunction %!demo %! fs = 11025; # arbitrary sample rate %! f0 = 100; # pulse train sample rate %! x = pulstran (0:1/fs:4/f0, 0:1/f0:4/f0, "gauspuls"); %! plot ([0:length(x)-1]*1000/fs, x); %! xlabel ("Time (ms)"); %! ylabel ("Amplitude"); %! title ("Gaussian pulse train at 10 ms intervals"); %!assert (gauspuls ([]), []) %!assert (gauspuls (zeros (10, 1)), ones (10, 1)) %!assert (gauspuls (-1:1), [0, 1, 0]) %!assert (gauspuls (0:1/100:0.3, 0.1), gauspuls ([0:1/100:0.3]', 0.1)') ## Test input validation %!error gauspuls () %!error gauspuls (1, 2, 3, 4) %!error gauspuls (1, -1) %!error gauspuls (1, 2j) %!error gauspuls (1, 1e3, 0) signal-1.4.5/inst/gaussian.m0000644000000000000000000000351514456505401014141 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} gaussian (@var{m}) ## @deftypefnx {Function File} {} gaussian (@var{m}, @var{a}) ## ## Return a Gaussian convolution window of length @var{m}. The width of the ## window is inversely proportional to the parameter @var{a}. Use larger ## @var{a} for a narrower window. Use larger @var{m} for longer tails. ## ## w = exp ( -(a*x)^2/2 ) ## ## for x = linspace ( -(m-1)/2, (m-1)/2, m ). ## ## Width a is measured in frequency units (sample rate/num samples). ## It should be f when multiplying in the time domain, but 1/f when ## multiplying in the frequency domain (for use in convolutions). ## @end deftypefn function w = gaussian (m, a) if (nargin < 1 || nargin > 2) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("gaussian: M must be a positive integer"); elseif (nargin == 1) a = 1; endif w = exp(-0.5*(([0:m-1]'-(m-1)/2)*a).^2); endfunction %!assert (gaussian (1), 1) %% Test input validation %!error gaussian () %!error gaussian (0.5) %!error gaussian (-1) %!error gaussian (ones (1, 4)) %!error gaussian (1, 2, 3) signal-1.4.5/inst/gausswin.m0000644000000000000000000000353614456505401014172 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} gausswin (@var{m}) ## @deftypefnx {Function File} {} gausswin (@var{m}, @var{a}) ## ## Return the filter coefficients of a Gaussian window of length @var{m}. ## The width of the window is inversely proportional to the parameter @var{a}. ## Use larger @var{a} for a narrow window. Use larger @var{m} for a smoother ## curve. ## ## w = exp ( -(a*x)^2/2 ) ## ## for x = linspace(-(m-1)/m, (m-1)/m, m) ## @end deftypefn function w = gausswin (m, a) if (nargin < 1 || nargin > 2) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("Octave:invalid-input-arg", ... "gausswin: M must be a positive integer"); elseif (nargin == 1) a = 2.5; endif if (m == 1) w = 1; else w = exp (-0.5 * (a / (m-1) * (-(m-1):2:(m-1))') .^ 2); endif endfunction %!assert (gausswin (1), 1) %!assert (gausswin (2), [exp(-3.125); exp(-3.125)]) %!assert (gausswin (3), [exp(-3.125); 1; exp(-3.125)]) ## Test input validation %!error gausswin () %!error gausswin (0.5) %!error gausswin (-1) %!error gausswin (ones (1, 4)) %!error gausswin (1, 2, 3) signal-1.4.5/inst/gmonopuls.m0000644000000000000000000000211314456505401014343 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} gmonopuls (@var{t},@var{fc}) ## Return the gaussian monopulse. ## @end deftypefn function y = gmonopuls(t, fc = 1e3) if (nargin<1 || nargin > 2), print_usage; endif if fc < 0 , error("fc must be positive"); endif y = 2*sqrt(exp(1)) .* pi.*t.*fc.*exp(-2 .* (pi.*t.*fc).^2); endfunction signal-1.4.5/inst/grpdelay.m0000644000000000000000000002740014456505401014135 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## Copyright (C) 2004 Julius O. Smith III ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{g}, @var{w}] =} grpdelay (@var{b}) ## @deftypefnx {Function File} {[@var{g}, @var{w}] =} grpdelay (@var{b}, @var{a}) ## @deftypefnx {Function File} {[@var{g}, @var{w}] =} grpdelay (@dots{}, @var{n}) ## @deftypefnx {Function File} {[@var{g}, @var{w}] =} grpdelay (@dots{}, @var{n}, "whole") ## @deftypefnx {Function File} {[@var{g}, @var{f}] =} grpdelay (@dots{}, @var{n}, @var{Fs}) ## @deftypefnx {Function File} {[@var{g}, @var{f}] =} grpdelay (@dots{}, @var{n}, "whole", @var{Fs}) ## @deftypefnx {Function File} {[@var{g}, @var{w}] =} grpdelay (@dots{}, @var{w}) ## @deftypefnx {Function File} {[@var{g}, @var{f}] =} grpdelay (@dots{}, @var{f}, @var{Fs}) ## @deftypefnx {Function File} {} grpdelay (@dots{}) ## Compute the group delay of a filter. ## ## [g, w] = grpdelay(b) ## returns the group delay g of the FIR filter with coefficients b. ## The response is evaluated at 512 angular frequencies between 0 and ## pi. w is a vector containing the 512 frequencies. ## The group delay is in units of samples. It can be converted ## to seconds by multiplying by the sampling period (or dividing by ## the sampling rate fs). ## ## [g, w] = grpdelay(b,a) ## returns the group delay of the rational IIR filter whose numerator ## has coefficients b and denominator coefficients a. ## ## [g, w] = grpdelay(b,a,n) ## returns the group delay evaluated at n angular frequencies. For fastest ## computation n should factor into a small number of small primes. ## ## [g, w] = grpdelay(b,a,n,'whole') ## evaluates the group delay at n frequencies between 0 and 2*pi. ## ## [g, f] = grpdelay(b,a,n,Fs) ## evaluates the group delay at n frequencies between 0 and Fs/2. ## ## [g, f] = grpdelay(b,a,n,'whole',Fs) ## evaluates the group delay at n frequencies between 0 and Fs. ## ## [g, w] = grpdelay(b,a,w) ## evaluates the group delay at frequencies w (radians per sample). ## ## [g, f] = grpdelay(b,a,f,Fs) ## evaluates the group delay at frequencies f (in Hz). ## ## grpdelay(...) ## plots the group delay vs. frequency. ## ## If the denominator of the computation becomes too small, the group delay ## is set to zero. (The group delay approaches infinity when ## there are poles or zeros very close to the unit circle in the z plane.) ## ## Theory: group delay, g(w) = -d/dw [arg@{H(e^jw)@}], is the rate of change of ## phase with respect to frequency. It can be computed as: ## ## @example ## d/dw H(e^-jw) ## g(w) = ------------- ## H(e^-jw) ## @end example ## ## where ## ## @example ## H(z) = B(z)/A(z) = sum(b_k z^k)/sum(a_k z^k). ## @end example ## ## By the quotient rule, ## ## @example ## A(z) d/dw B(z) - B(z) d/dw A(z) ## d/dw H(z) = ------------------------------- ## A(z) A(z) ## @end example ## ## Substituting into the expression above yields: ## ## @example ## A dB - B dA ## g(w) = ----------- = dB/B - dA/A ## A B ## @end example ## ## Note that, ## ## @example ## d/dw B(e^-jw) = sum(k b_k e^-jwk) ## d/dw A(e^-jw) = sum(k a_k e^-jwk) ## @end example ## ## which is just the FFT of the coefficients multiplied by a ramp. ## ## As a further optimization when nfft>>length(a), the IIR filter (b,a) ## is converted to the FIR filter conv(b,fliplr(conj(a))). ## For further details, see ## http://ccrma.stanford.edu/~jos/filters/Numerical_Computation_Group_Delay.html ## @end deftypefn function [gd, w] = grpdelay (b, a = 1, nfft = 512, whole, Fs) if (nargin < 1 || nargin > 5) print_usage (); endif HzFlag = false; if (length (nfft) > 1) if (nargin > 4) print_usage (); elseif (nargin > 3) ## grpdelay (B, A, F, Fs) Fs = whole; HzFlag = true; else ## grpdelay (B, A, W) Fs = 1; endif w = 2*pi*nfft/Fs; nfft = length (w) * 2; whole = ""; else if (nargin < 5) Fs = 1; # return w in radians per sample if (nargin < 4) whole = ""; elseif (! ischar (whole)) Fs = whole; HzFlag = true; whole = ""; endif if (nargin < 3) nfft = 512; endif if (nargin < 2) a = 1; endif else HzFlag = true; endif if (isempty (nfft)) nfft = 512; endif if (! strcmp (whole, "whole")) nfft = 2*nfft; endif w = Fs*[0:nfft-1]/nfft; endif if (! HzFlag) w = w * 2 * pi; endif ## Make sure both are row vector a = a(:).'; b = b(:).'; oa = length (a) -1; # order of a(z) if (oa < 0) # a can be [] a = 1; oa = 0; endif ob = length (b) -1; # order of b(z) if (ob < 0) # b can be [] as well b = 1; ob = 0; endif oc = oa + ob; # order of c(z) c = conv (b, fliplr (conj (a))); # c(z) = b(z)*conj(a)(1/z)*z^(-oa) cr = c.*(0:oc); # cr(z) = derivative of c wrt 1/z num = fft (cr, nfft); den = fft (c, nfft); minmag = 10*eps; polebins = find (abs (den) < minmag); for b = polebins warning ("signal:grpdelay-singularity", "grpdelay: setting group delay to 0 at singularity"); num(b) = 0; den(b) = 1; ## try to preserve angle: ## db = den(b); ## den(b) = minmag*abs(num(b))*exp(j*atan2(imag(db),real(db))); ## warning(sprintf('grpdelay: den(b) changed from %f to %f',db,den(b))); endfor gd = real (num ./ den) - oa; if (! strcmp (whole, "whole")) ns = nfft/2; # Matlab convention ... should be nfft/2 + 1 gd = gd(1:ns); w = w(1:ns); else ns = nfft; # used in plot below endif ## compatibility gd = gd(:); w = w(:); if (nargout == 0) unwind_protect grid ("on"); # grid() should return its previous state if (HzFlag) funits = "Hz"; else funits = "radian/sample"; endif xlabel (["Frequency (" funits ")"]); ylabel ("Group delay (samples)"); plot (w(1:ns), gd(1:ns), ";;"); unwind_protect_cleanup grid ("on"); end_unwind_protect endif endfunction ## ------------------------ DEMOS ----------------------- %!demo % 1 %! %-------------------------------------------------------------- %! % From Oppenheim and Schafer, a single zero of radius r=0.9 at %! % angle pi should have a group delay of about -9 at 1 and 1/2 %! % at zero and 2*pi. %! %-------------------------------------------------------------- %! grpdelay([1 0.9],[],512,'whole',1); %! hold on; %! xlabel('Normalized Frequency (cycles/sample)'); %! stem([0, 0.5, 1],[0.5, -9, 0.5],'*b;target;'); %! hold off; %! title ('Zero at z = -0.9'); %! %!demo % 2 %! %-------------------------------------------------------------- %! % confirm the group delays approximately meet the targets %! % don't worry that it is not exact, as I have not entered %! % the exact targets. %! %-------------------------------------------------------------- %! b = poly([1/0.9*exp(1i*pi*0.2), 0.9*exp(1i*pi*0.6)]); %! a = poly([0.9*exp(-1i*pi*0.6), 1/0.9*exp(-1i*pi*0.2)]); %! grpdelay(b,a,512,'whole',1); %! hold on; %! xlabel('Normalized Frequency (cycles/sample)'); %! stem([0.1, 0.3, 0.7, 0.9], [9, -9, 9, -9],'*b;target;'); %! hold off; %! title ('Two Zeros and Two Poles'); %!demo % 3 %! %-------------------------------------------------------------- %! % fir lowpass order 40 with cutoff at w=0.3 and details of %! % the transition band [.3, .5] %! %-------------------------------------------------------------- %! subplot(211); %! Fs = 8000; % sampling rate %! Fc = 0.3*Fs/2; % lowpass cut-off frequency %! nb = 40; %! b = fir1(nb,2*Fc/Fs); % matlab freq normalization: 1=Fs/2 %! [H,f] = freqz(b,1,[],1); %! [gd,f] = grpdelay(b,1,[],1); %! plot(f,20*log10(abs(H))); %! title(sprintf('b = fir1(%d,2*%d/%d);',nb,Fc,Fs)); %! xlabel('Normalized Frequency (cycles/sample)'); %! ylabel('Amplitude Response (dB)'); %! grid('on'); %! subplot(212); %! del = nb/2; % should equal this %! plot(f,gd); %! title(sprintf('Group Delay in Pass-Band (Expect %d samples)',del)); %! ylabel('Group Delay (samples)'); %! axis([0, 0.2, del-1, del+1]); %!demo % 4 %! %-------------------------------------------------------------- %! % IIR bandstop filter has delays at [1000, 3000] %! %-------------------------------------------------------------- %! Fs = 8000; %! [b, a] = cheby1(3, 3, 2*[1000, 3000]/Fs, 'stop'); %! [H,f] = freqz(b,a,[],Fs); %! [gd,f] = grpdelay(b,a,[],Fs); %! subplot(211); %! plot(f,abs(H)); %! title('[b,a] = cheby1(3, 3, 2*[1000, 3000]/Fs, "stop");'); %! xlabel('Frequency (Hz)'); %! ylabel('Amplitude Response'); %! grid('on'); %! subplot(212); %! plot(f,gd); %! title('[gd,f] = grpdelay(b,a,[],Fs);'); %! ylabel('Group Delay (samples)'); % ------------------------ TESTS ----------------------- %!test % 00 %! [gd1,w] = grpdelay([0,1]); %! [gd2,w] = grpdelay([0,1],1); %! assert(gd1,gd2,10*eps); %!test % 0A %! [gd,w] = grpdelay([0,1],1,4); %! assert(gd,[1;1;1;1]); %! assert(w,pi/4*[0:3]',10*eps); %!test % 0B %! [gd,w] = grpdelay([0,1],1,4,'whole'); %! assert(gd,[1;1;1;1]); %! assert(w,pi/2*[0:3]',10*eps); %!test % 0C %! [gd,f] = grpdelay([0,1],1,4,0.5); %! assert(gd,[1;1;1;1]); %! assert(f,1/16*[0:3]',10*eps); %!test % 0D %! [gd,w] = grpdelay([0,1],1,4,'whole',1); %! assert(gd,[1;1;1;1]); %! assert(w,1/4*[0:3]',10*eps); %!test % 0E %! [gd,f] = grpdelay([1 -0.9j],[],4,'whole',1); %! gd0 = 0.447513812154696; gdm1 =0.473684210526316; %! assert(gd,[gd0;-9;gd0;gdm1],20*eps); %! assert(f,1/4*[0:3]',10*eps); %!test % 1A: %! gd= grpdelay(1,[1,.9],2*pi*[0,0.125,0.25,0.375]); %! assert(gd, [-0.47368;-0.46918;-0.44751;-0.32316],1e-5); %!test % 1B: %! gd= grpdelay(1,[1,.9],[0,0.125,0.25,0.375],1); %! assert(gd, [-0.47368;-0.46918;-0.44751;-0.32316],1e-5); %!test % 2: %! gd = grpdelay([1,2],[1,0.5,.9],4); %! assert(gd,[-0.29167;-0.24218;0.53077;0.40658],1e-5); %!test % 3 %! b1=[1,2];a1f=[0.25,0.5,1];a1=fliplr(a1f); %! % gd1=grpdelay(b1,a1,4); %! gd=grpdelay(conv(b1,a1f),1,4)-2; %! assert(gd, [0.095238;0.239175;0.953846;1.759360],1e-5); %!test % 4 %! warning ("off", "signal:grpdelay-singularity", "local"); %! Fs = 8000; %! [b, a] = cheby1(3, 3, 2*[1000, 3000]/Fs, 'stop'); %! [h, w] = grpdelay(b, a, 256, 'half', Fs); %! [h2, w2] = grpdelay(b, a, 512, 'whole', Fs); %! assert (size(h), size(w)); %! assert (length(h), 256); %! assert (size(h2), size(w2)); %! assert (length(h2), 512); %! assert (h, h2(1:256)); %! assert (w, w2(1:256)); %!test % 5 %! a = [1 0 0.9]; %! b = [0.9 0 1]; %! [dh, wf] = grpdelay(b, a, 512, 'whole'); %! [da, wa] = grpdelay(1, a, 512, 'whole'); %! [db, wb] = grpdelay(b, 1, 512, 'whole'); %! assert(dh,db+da,1e-5); ## test for bug #39133 (do not fail for row or column vector) %!test %! DR= [1.00000 -0.00000 -3.37219 0.00000 ... %! 5.45710 -0.00000 -5.24394 0.00000 ... %! 3.12049 -0.00000 -1.08770 0.00000 0.17404]; %! N = [-0.0139469 -0.0222376 0.0178631 0.0451737 ... %! 0.0013962 -0.0259712 0.0016338 0.0165189 ... %! 0.0115098 0.0095051 0.0043874]; %! assert (nthargout (1:2, @grpdelay, N, DR, 1024), %! nthargout (1:2, @grpdelay, N', DR', 1024)); signal-1.4.5/inst/hann.m0000644000000000000000000000402314456505401013246 0ustar0000000000000000## Copyright (C) 2014-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} hann (@var{m}) ## @deftypefnx {Function File} {} hann (@var{m}, "periodic") ## @deftypefnx {Function File} {} hann (@var{m}, "symmetric") ## Return the filter coefficients of a Hanning window of length @var{m}. ## ## If the optional argument @code{"periodic"} is given, the periodic form ## of the window is returned. This is equivalent to the window of length ## @var{m}+1 with the last coefficient removed. The optional argument ## @code{"symmetric"} is equivalent to not specifying a second argument. ## ## This function exists for @sc{matlab} compatibility only, and is equivalent ## to @code{hanning (@var{m})}. ## ## @seealso{hanning} ## @end deftypefn function w = hann (varargin) if (nargin < 1 || nargin > 2) print_usage (); endif w = hanning (varargin{:}); endfunction %!assert (hann (1), 1); %!assert (hann (2), zeros (2, 1)); %!assert (hann (16), flipud (hann (16)), 10*eps); %!assert (hann (15), flipud (hann (15)), 10*eps); %!test %! N = 15; %! A = hann (N); %! assert (A(ceil (N/2)), 1); %!assert (hann (15), hann (15, "symmetric")); %!assert (hann (16)(1:15), hann (15, "periodic")); %!test %! N = 16; %! A = hann (N, "periodic"); %! assert (A (N/2 + 1), 1); %% Test input validation %!error hann () %!error hann (0.5) %!error hann (-1) %!error hann (1, "invalid") signal-1.4.5/inst/hilbert.m0000644000000000000000000000755714456505401013772 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## Copyright (C) 2007 Peter L. Soendergaard ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{h} =} hilbert (@var{f}, @var{N}, @var{dim}) ## Analytic extension of real valued signal. ## ## @code{@var{h} = hilbert (@var{f})} computes the extension of the real ## valued signal @var{f} to an analytic signal. If @var{f} is a matrix, ## the transformation is applied to each column. For N-D arrays, ## the transformation is applied to the first non-singleton dimension. ## ## @code{real (@var{h})} contains the original signal @var{f}. ## @code{imag (@var{h})} contains the Hilbert transform of @var{f}. ## ## @code{hilbert (@var{f}, @var{N})} does the same using a length @var{N} ## Hilbert transform. The result will also have length @var{N}. ## ## @code{hilbert (@var{f}, [], @var{dim})} or ## @code{hilbert (@var{f}, @var{N}, @var{dim})} does the same along ## dimension @var{dim}. ## @end deftypefn function f=hilbert(f, N = [], dim = []) ## ------ PRE: initialization and dimension shifting --------- if (nargin<1 || nargin>3) print_usage; endif if ~isreal(f) warning ('HILBERT: ignoring imaginary part of signal'); f = real (f); endif D=ndims(f); ## Dummy assignment. order=1; if isempty(dim) dim=1; if sum(size(f)>1)==1 ## We have a vector, find the dimension where it lives. dim=find(size(f)>1); endif else if (numel(dim)~=1 || ~isnumeric(dim)) error('HILBERT: dim must be a scalar.'); endif if rem(dim,1)~=0 error('HILBERT: dim must be an integer.'); endif if (dim<1) || (dim>D) error('HILBERT: dim must be in the range from 1 to %d.',D); endif endif if (numel(N)>1 || ~isnumeric(N)) error('N must be a scalar.'); elseif (~isempty(N) && rem(N,1)~=0) error('N must be an integer.'); endif if dim>1 order=[dim, 1:dim-1,dim+1:D]; ## Put the desired dimension first. f=permute(f,order); endif Ls=size(f,1); ## If N is empty it is set to be the length of the transform. if isempty(N) N=Ls; endif ## Remember the exact size for later and modify it for the new length permutedsize=size(f); permutedsize(1)=N; ## Reshape f to a matrix. f=reshape(f,size(f,1),numel(f)/size(f,1)); W=size(f,2); if ~isempty(N) f=postpad(f,N); endif ## ------- actual computation ----------------- if N>2 f=fft(f); if rem(N,2)==0 f=[f(1,:); 2*f(2:N/2,:); f(N/2+1,:); zeros(N/2-1,W)]; else f=[f(1,:); 2*f(2:(N+1)/2,:); zeros((N-1)/2,W)]; endif f=ifft(f); endif ## ------- POST: Restoration of dimensions ------------ ## Restore the original, permuted shape. f=reshape(f,permutedsize); if dim>1 ## Undo the permutation. f=ipermute(f,order); endif endfunction %!demo %! ## notice that the imaginary signal is phase-shifted 90 degrees %! t=linspace(0,10,256); %! z = hilbert(sin(2*pi*0.5*t)); %! grid on; plot(t,real(z),';real;',t,imag(z),';imag;'); %!demo %! ## the magnitude of the hilbert transform eliminates the carrier %! t=linspace(0,10,1024); %! x=5*cos(0.2*t).*sin(100*t); %! grid on; plot(t,x,'g;z;',t,abs(hilbert(x)),'b;|hilbert(z)|;'); signal-1.4.5/inst/idct.m0000644000000000000000000000501114456505401013243 0ustar0000000000000000## Copyright (C) 2001 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} idct (@var{x}) ## @deftypefnx {Function File} {@var{y} =} idct (@var{x}, @var{n}) ## Compute the inverse discrete cosine transform of @var{x}. If @var{n} is ## given, then @var{x} is padded or trimmed to length @var{n} before computing ## the transform. If @var{x} is a matrix, compute the transform along the ## columns of the the matrix. The transform is faster if @var{x} is ## real-valued and even length. ## ## The inverse discrete cosine transform @var{x} can be defined as follows: ## ## @example ## N-1 ## x[n] = sum w(k) X[k] cos (pi (2n+1) k / 2N ), n = 0, ..., N-1 ## k=0 ## @end example ## ## with w(0) = sqrt(1/N) and w(k) = sqrt(2/N), k = 1, ..., N-1 ## ## @seealso{dct, dct2, idct2, dctmtx} ## @end deftypefn function y = idct (x, n) if (nargin < 1 || nargin > 2) print_usage; endif realx = isreal(x); transpose = (rows (x) == 1); if transpose, x = x (:); endif [nr, nc] = size (x); if nargin == 1 n = nr; elseif n > nr x = [ x ; zeros(n-nr,nc) ]; elseif n < nr x (n-nr+1 : n, :) = []; endif if ( realx && rem (n, 2) == 0 ) w = [ sqrt(n/4); sqrt(n/2)*exp((1i*pi/2/n)*[1:n-1]') ] * ones (1, nc); y = ifft (w .* x); y([1:2:n, n:-2:1], :) = 2*real(y); elseif n == 1 y = x; else ## reverse the steps of dct using inverse operations ## 1. undo post-fft scaling w = [ sqrt(4*n); sqrt(2*n)*exp((1i*pi/2/n)*[1:n-1]') ] * ones (1, nc); y = x.*w; ## 2. reconstruct fft result and invert it w = exp(-1i*pi*[n-1:-1:1]'/n) * ones(1,nc); y = ifft ( [ y ; zeros(1,nc); y(n:-1:2,:).*w ] ); ## 3. keep only the original data; toss the reversed copy y = y(1:n, :); if (realx) y = real (y); endif endif if transpose, y = y.'; endif endfunction signal-1.4.5/inst/idct2.m0000644000000000000000000000274714456505401013342 0ustar0000000000000000## Copyright (C) 2001 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} idct2 (@var{x}) ## @deftypefnx {Function File} {@var{y} =} idct2 (@var{x}, @var{m}, @var{n}) ## @deftypefnx {Function File} {@var{y} =} idct2 (@var{x}, [@var{m}, @var{n}]) ## Compute the inverse 2-D discrete cosine transform of matrix @var{x}. ## If @var{m} and @var{n} are specified, the input is either padded or truncated ## to have @var{m} rows and @var{n} columns. ## @end deftypefn function y = idct2 (x, m, n) if (nargin < 1 || nargin > 3) print_usage; endif if nargin == 1 [m, n] = size (x); elseif (nargin == 2) n = m (2); m = m (1); endif if m == 1 y = idct (x.', n).'; elseif n == 1 y = idct (x, m); else y = idct (idct (x, m).', n).'; endif endfunction signal-1.4.5/inst/idst.m0000644000000000000000000000147014456505401013270 0ustar0000000000000000## Author: Paul Kienzle (2006) ## This program is granted to the public domain. ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} idst (@var{x}) ## @deftypefnx {Function File} {@var{y} =} idst (@var{x}, @var{n}) ## Computes the inverse type I discrete sine transform of @var{y}. If @var{n} is ## given, then @var{y} is padded or trimmed to length @var{n} before computing ## the transform. If @var{y} is a matrix, compute the transform along the ## columns of the the matrix. ## @seealso{dst} ## @end deftypefn function x = idst (y, n) if (nargin < 1 || nargin > 2) print_usage; endif if nargin == 1, n = size(y,1); if n==1, n = size(y,2); endif endif x = dst(y, n) * 2/(n+1); endfunction %!test %! x = log(gausswin(32)); %! assert(x, idst(dst(x)), 100*eps) signal-1.4.5/inst/ifht.m0000644000000000000000000000402614456505401013257 0ustar0000000000000000## Copyright (C) 2008 Muthiah Annamalai ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{m} =} ifht (@var{d}, @var{n}, @var{dim}) ## Calculate the inverse Fast Hartley Transform of real input @var{d}. If ## @var{d} is a matrix, the inverse Hartley transform is calculated along the ## columns by default. The options @var{n} and @var{dim} are similar to the ## options of FFT function. ## ## The forward and inverse Hartley transforms are the same (except for a ## scale factor of 1/N for the inverse hartley transform), but ## implemented using different functions. ## ## The definition of the forward hartley transform for vector d, ## @math{ ## m[K] = 1/N \sum_{i=0}^{N-1} d[i]*(cos[K*2*pi*i/N] + sin[K*2*pi*i/N]), for 0 <= K < N. ## m[K] = 1/N \sum_{i=0}^{N-1} d[i]*CAS[K*i], for 0 <= K < N. } ## ## @example ## ifht(1:4) ## @end example ## @seealso{fht, fft} ## @end deftypefn function m = ifht( d, n, dim ) if ( nargin < 1 ) print_usage(); endif if ( nargin == 3 ) Y = ifft(d,n,dim); elseif ( nargin == 2 ) Y = ifft(d,n); else Y = ifft(d); endif m = real(Y) + imag(Y); ## -- Traditional -- ## N = length(d); ## for K = 1:N ## i = 0:N-1; ## t = (2*pi*(K-1).*i/N); ## ker = (cos(t) + sin(t)); ## val = dot(d,ker)./N; ## m(K) = val; ## endfor endfunction %!assert(ifht(fht(1:4)),[1 2 3 4]) signal-1.4.5/inst/ifwht.m0000644000000000000000000000472014456505401013447 0ustar0000000000000000## Copyright (C) 2013-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} ifwht (@var{x}) ## @deftypefnx {Function File} {} ifwht (@var{x}, @var{n}) ## @deftypefnx {Function File} {} ifwht (@var{x}, @var{n}, @var{order}) ## Compute the inverse Walsh-Hadamard transform of @var{x} using the ## Fast Walsh-Hadamard Transform (FWHT) algorithm. If the input is a ## matrix, the inverse FWHT is calculated along the columns of @var{x}. ## ## The number of elements of @var{x} must be a power of 2; if not, the ## input will be extended and filled with zeros. If a second argument ## is given, the input is truncated or extended to have length @var{n}. ## ## The third argument specifies the @var{order} in which the returned ## inverse Walsh-Hadamard transform coefficients should be arranged. ## The @var{order} may be any of the following strings: ## ## @table @asis ## @item "sequency" ## The coefficients are returned in sequency order. This is the default ## if @var{order} is not given. ## ## @item "hadamard" ## The coefficients are returned in Hadamard order. ## ## @item "dyadic" ## The coefficients are returned in Gray code order. ## @end table ## ## @seealso{fwht} ## @end deftypefn function y = ifwht (x, n, order) if (nargin < 1 || nargin > 3) print_usage (); elseif (nargin == 1) n = order = []; elseif (nargin == 2) order = []; endif y = __fwht_opts__ ("ifwht", x, n, order); endfunction %!assert (isempty (ifwht ([]))); %!assert (ifwht (zeros (16)), zeros (16)); %!assert (ifwht ([1; (zeros (15, 1))]), ones (16, 1)); %!assert (ifwht (zeros (17, 1)), zeros (32, 1)); %!assert (ifwht ([0 0 0 0 0 0 0 1]), [1 -1 1 -1 1 -1 1 -1]); %% Test input validation %!error ifwht (); %!error ifwht (1, 2, 3, 4); %!error ifwht (0, 0); %!error ifwht (0, 5); %!error ifwht (0, [], "invalid"); signal-1.4.5/inst/iirlp2mb.m0000644000000000000000000002754414456505401014057 0ustar0000000000000000## Copyright (C) 2011 Alan J. Greenberger ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## IIR Low Pass Filter to Multiband Filter Transformation ## ## [Num,Den,AllpassNum,AllpassDen] = iirlp2mb(B,A,Wo,Wt) ## [Num,Den,AllpassNum,AllpassDen] = iirlp2mb(B,A,Wo,Wt,Pass) ## ## Num,Den: numerator,denominator of the transformed filter ## AllpassNum,AllpassDen: numerator,denominator of allpass transform, ## B,A: numerator,denominator of prototype low pass filter ## Wo: normalized_angular_frequency/pi to be transformed ## Wt: [phi=normalized_angular_frequencies]/pi target vector ## Pass: This parameter may have values 'pass' or 'stop'. If ## not given, it defaults to the value of 'pass'. ## ## With normalized ang. freq. targets 0 < phi(1) < ... < phi(n) < pi radians ## ## for Pass == 'pass', the target multiband magnitude will be: ## -------- ---------- -----------... ## / \ / \ / . ## 0 phi(1) phi(2) phi(3) phi(4) phi(5) (phi(6)) pi ## ## for Pass == 'stop', the target multiband magnitude will be: ## ------- --------- ----------... ## \ / \ / . ## 0 phi(1) phi(2) phi(3) phi(4) (phi(5)) pi ## ## Example of use: ## [B, A] = butter(6, 0.5); ## [Num, Den] = iirlp2mb(B, A, 0.5, [.2 .4 .6 .8]); function [Num,Den,AllpassNum,AllpassDen] = iirlp2mb(varargin) usage = sprintf( "%s: Usage: [Num,Den,AllpassNum,AllpassDen]=iirlp2mb(B,A,Wo,Wt[,Pass])\n" ,mfilename()); B = varargin{1}; # numerator polynomial of prototype low pass filter A = varargin{2}; # denominator polynomial of prototype low pass filter Wo = varargin{3}; # (normalized angular frequency)/pi to be transformed Wt = varargin{4}; # vector of (norm. angular frequency)/pi transform targets # [phi(1) phi(2) ... ]/pi if(nargin < 4 || nargin > 5) error("%s",usage) endif if(nargin == 5) Pass = varargin{5}; switch(Pass) case 'pass' pass_stop = -1; case 'stop' pass_stop = 1; otherwise error("Pass must be 'pass' or 'stop'\n%s",usage) endswitch else pass_stop = -1; # Pass == 'pass' is the default endif if(Wo <= 0) error("Wo is %f <= 0\n%s",Wo,usage); endif if(Wo >= 1) error("Wo is %f >= 1\n%s",Wo,usage); endif oWt = 0; for i = 1 : length(Wt) if(Wt(i) <= 0) error("Wt(%d) is %f <= 0\n%s",i,Wt(i),usage); endif if(Wt(i) >= 1) error("Wt(%d) is %f >= 1\n%s",i,Wt(i),usage); endif if(Wt(i) <= oWt) error("Wt(%d) = %f, not monotonically increasing\n%s",i,Wt(i),usage); else oWt = Wt(i); endif endfor ## B(z) ## Inputs B,A specify the low pass IIR prototype filter G(z) = ---- . ## A(z) ## This module transforms G(z) into a multiband filter using the iterative ## algorithm from: ## [FFM] G. Feyh, J. Franchitti, and C. Mullis, "All-Pass Filter ## Interpolation and Frequency Transformation Problem", Proceedings 20th ## Asilomar Conference on Signals, Systems and Computers, Nov. 1986, pp. ## 164-168, IEEE. ## [FFM] moves the prototype filter position at normalized angular frequency ## .5*pi to the places specified in the Wt vector times pi. In this module, ## a generalization allows the position to be moved on the prototype filter ## to be specified as Wo*pi instead of being fixed at .5*pi. This is ## implemented using two successive allpass transformations. ## KK(z) ## In the first stage, find allpass J(z) = ---- such that ## K(z) ## jWo*pi -j.5*pi ## J(e ) = e (low pass to low pass transformation) ## ## PP(z) ## In the second stage, find allpass H(z) = ---- such that ## P(z) ## jWt(k)*pi -j(2k - 1)*.5*pi ## H(e ) = e (low pass to multiband transformation) ## ## ^ ## The variable PP used here corresponds to P in [FFM]. ## len = length(P(z)) == length(PP(z)), the number of polynomial coefficients ## ## len 1-i len 1-i ## P(z) = SUM P(i)z ; PP(z) = SUM PP(i)z ; PP(i) == P(len + 1 - i) ## i=1 i=1 (allpass condition) ## Note: (len - 1) == n in [FFM] eq. 3 ## ## The first stage computes the denominator of an allpass for translating ## from a prototype with position .5 to one with a position of Wo. It has the ## form: ## -1 ## K(2) - z ## ----------- ## -1 ## 1 - K(2)z ## ## From the low pass to low pass transformation in Table 7.1 p. 529 of A. ## Oppenheim and R. Schafer, Discrete-Time Signal Processing 3rd edition, ## Prentice Hall 2010, one can see that the denominator of an allpass for ## going in the opposite direction can be obtained by a sign reversal of the ## second coefficient, K(2), of the vector K (the index 2 not to be confused ## with a value of z, which is implicit). ## The first stage allpass denominator computation K = apd([pi * Wo]); ## The second stage allpass computation phi = pi * Wt; # vector of normalized angular frequencies between 0 and pi P = apd(phi); # calculate denominator of allpass for this target vector PP = revco(P); # numerator of allpass has reversed coefficients of P ## The total allpass filter from the two consecutive stages can be written as ## PP ## K(2) - --- ## P P ## ----------- * --- ## PP P ## 1 - K(2)--- ## P AllpassDen = P - (K(2) * PP); AllpassDen /= AllpassDen(1); # normalize AllpassNum = pass_stop * revco(AllpassDen); [Num,Den] = transform(B,A,AllpassNum,AllpassDen,pass_stop); endfunction function [Num,Den] = transform(B,A,PP,P,pass_stop) ## Given G(Z) = B(Z)/A(Z) and allpass H(z) = PP(z)/P(z), compute G(H(z)) ## For Pass = 'pass', transformed filter is: ## 2 nb-1 ## B1 + B2(PP/P) + B3(PP/P)^ + ... + Bnb(PP/P)^ ## ------------------------------------------------- ## 2 na-1 ## A1 + A2(PP/P) + A3(PP/P)^ + ... + Ana(PP/P)^ ## For Pass = 'stop', use powers of (-PP/P) ## na = length(A); # the number of coefficients in A nb = length(B); # the number of coefficients in B ## common low pass iir filters have na == nb but in general might not n = max(na,nb); # the greater of the number of coefficients ## n-1 ## Multiply top and bottom by P^ yields: ## ## n-1 n-2 2 n-3 nb-1 n-nb ## B1(P^ ) + B2(PP)(P^ ) + B3(PP^ )(P^ ) + ... + Bnb(PP^ )(P^ ) ## --------------------------------------------------------------------- ## n-1 n-2 2 n-3 na-1 n-na ## A1(P^ ) + A2(PP)(P^ ) + A3(PP^ )(P^ ) + ... + Ana(PP^ )(P^ ) ## Compute and store powers of P as a matrix of coefficients because we will ## need to use them in descending power order global Ppower; # to hold coefficients of powers of P, access inside ppower() np = length(P); powcols = np + (np-1)*(n-2); # number of coefficients in P^(n-1) ## initialize to "Not Available" with n-1 rows for powers 1 to (n-1) and ## the number of columns needed to hold coefficients for P^(n-1) Ppower = NA(n-1,powcols); Ptemp = P; # start with P to the 1st power for i = 1 : n-1 # i is the power for j = 1 : length(Ptemp) # j is the coefficient index for this power Ppower(i,j) = Ptemp(j); endfor Ptemp = conv(Ptemp,P); # increase power of P by one endfor ## Compute numerator and denominator of transformed filter Num = []; Den = []; for i = 1 : n ## n-i ## Regenerate P^ (p_pownmi) if((n-i) == 0) p_pownmi = [1]; else p_pownmi = ppower(n-i,powcols); endif ## i-1 ## Regenerate PP^ (pp_powim1) if(i == 1) pp_powim1 = [1]; else pp_powim1 = revco(ppower(i-1,powcols)); endif if(i <= nb) Bterm = (pass_stop^(i-1))*B(i)*conv(pp_powim1,p_pownmi); Num = polysum(Num,Bterm); endif if(i <= na) Aterm = (pass_stop^(i-1))*A(i)*conv(pp_powim1,p_pownmi); Den = polysum(Den,Aterm); endif endfor ## Scale both numerator and denominator to have Den(1) = 1 temp = Den(1); for i = 1 : length(Den) Den(i) = Den(i) / temp; endfor for i = 1 : length(Num) Num(i) = Num(i) / temp; endfor endfunction function P = apd(phi) # all pass denominator ## Given phi, a vector of normalized angular frequency transformation targets, ## return P, the denominator of an allpass H(z) lenphi = length(phi); Pkm1 = 1; # P0 initial condition from [FFM] eq. 22 for k = 1 : lenphi P = pk(Pkm1, k, phi(k)); # iterate Pkm1 = P; endfor endfunction function Pk = pk(Pkm1, k, phik) # kth iteration of P(z) ## Given Pkminus1, k, and phi(k) in radians , return Pk ## ## From [FFM] eq. 19 : k ## Pk = (z+1 )sin(phi(k)/2)Pkm1 - (-1) (z-1 )cos(phi(k)/2)PPkm1 ## Factoring out z ## -1 k -1 ## = z((1+z )sin(phi(k)/2)Pkm1 - (-1) (1-z )cos(phi(k)/2)PPkm1) ## PPk can also have z factored out. In H=PP/P, z in PPk will cancel z in Pk, ## so just leave out. Use ## -1 k -1 ## PK = (1+z )sin(phi(k)/2)Pkm1 - (-1) (1-z )cos(phi(k)/2)PPkm1 ## (expand) k ## = sin(phi(k)/2)Pkm1 - (-1) cos(phi(k)/2)PPkm1 ## ## -1 k -1 ## + z sin(phi(k)/2)Pkm1 + (-1) z cos(phi(k)/2)PPkm1 Pk = zeros(1,k+1); # there are k+1 coefficients in Pk sin_k = sin(phik/2); cos_k = cos(phik/2); for i = 1 : k Pk(i) += sin_k * Pkm1(i) - ((-1)^k * cos_k * Pkm1(k+1-i)); ## ## -1 ## Multiplication by z just shifts by one coefficient Pk(i+1) += sin_k * Pkm1(i) + ((-1)^k * cos_k * Pkm1(k+1-i)); endfor ## now normalize to Pk(1) = 1 (again will cancel with same factor in PPk) Pk1 = Pk(1); for i = 1 : k+1 Pk(i) = Pk(i) / Pk1; endfor endfunction function PP = revco(p) # reverse components of vector l = length(p); for i = 1 : l PP(l + 1 - i) = p(i); endfor endfunction function p = ppower(i,powcols) # Regenerate ith power of P from stored PPower global Ppower if(i == 0) p = 1; else p = []; for j = 1 : powcols if(isna(Ppower(i,j))) break; endif p = horzcat(p, Ppower(i,j)); endfor endif endfunction function poly = polysum(p1,p2) # add polynomials of possibly different length n1 = length(p1); n2 = length(p2); if(n1 > n2) ## pad p2 p2 = horzcat(p2, zeros(1,n1-n2)); elseif(n2 > n1) ## pad p1 p1 = horzcat(p1, zeros(1,n2-n1)); endif poly = p1 + p2; endfunction signal-1.4.5/inst/impinvar.m0000644000000000000000000001276414456505401014162 0ustar0000000000000000## Copyright (C) 2007 R.G.H. Eschauzier ## Copyright (C) 2011 CarnĂ« Draug ## Copyright (C) 2011 Juan Pablo Carbajal ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{b_out}, @var{a_out}] =} impinvar (@var{b}, @var{a}, @var{fs}, @var{tol}) ## @deftypefnx {Function File} {[@var{b_out}, @var{a_out}] =} impinvar (@var{b}, @var{a}, @var{fs}) ## @deftypefnx {Function File} {[@var{b_out}, @var{a_out}] =} impinvar (@var{b}, @var{a}) ## Converts analog filter with coefficients @var{b} and @var{a} to digital, ## conserving impulse response. ## ## If @var{fs} is not specified, or is an empty vector, it defaults to 1Hz. ## ## If @var{tol} is not specified, it defaults to 0.0001 (0.1%) ## This function does the inverse of impinvar so that the following example should ## restore the original values of @var{a} and @var{b}. ## ## @command{invimpinvar} implements the reverse of this function. ## @example ## [b, a] = impinvar (b, a); ## [b, a] = invimpinvar (b, a); ## @end example ## ## Reference: Thomas J. Cavicchi (1996) ``Impulse invariance and multiple-order ## poles''. IEEE transactions on signal processing, Vol 44 (9): 2344--2347 ## ## @seealso{bilinear, invimpinvar} ## @end deftypefn function [b_out, a_out] = impinvar (b_in, a_in, fs = 1, tol = 0.0001) if (nargin <2) print_usage; endif ## to be compatible with the matlab implementation where an empty vector can ## be used to get the default if (isempty(fs)) ts = 1; else ts = 1/fs; # we should be using sampling frequencies to be compatible with Matlab endif [r_in, p_in, k_in] = residue(b_in, a_in); # partial fraction expansion n = length(r_in); # Number of poles/residues if (length(k_in)>0) # Greater than zero means we cannot do impulse invariance error("Order numerator >= order denominator"); endif r_out = zeros(1,n); # Residues of H(z) p_out = zeros(1,n); # Poles of H(z) k_out = 0; # Constant term of H(z) i=1; while (i<=n) m = 1; first_pole = p_in(i); # Pole in the s-domain while (i ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{x}, @var{t}] =} impz (@var{b}) ## @deftypefnx {Function File} {[@var{x}, @var{t}] =} impz (@var{b}, @var{a}) ## @deftypefnx {Function File} {[@var{x}, @var{t}] =} impz (@var{b}, @var{a}, @var{n}) ## @deftypefnx {Function File} {[@var{x}, @var{t}] =} impz (@var{b}, @var{a}, @var{n}, @var{fs}) ## @deftypefnx {Function File} {} impz (@dots{}) ## ## Generate impulse-response characteristics of the filter. The filter ## coefficients correspond to the the z-plane rational function with ## numerator b and denominator a. If a is not specified, it defaults to ## 1. If n is not specified, or specified as [], it will be chosen such ## that the signal has a chance to die down to -120dB, or to not explode ## beyond 120dB, or to show five periods if there is no significant ## damping. If no return arguments are requested, plot the results. ## ## @seealso{freqz, zplane} ## @end deftypefn ## FIXME: Call equivalent function from control toolbox since it is ## probably more sophisticated than this one, and since it ## is silly to maintain two different versions of essentially ## the same thing. function [x_r, t_r] = impz(b, a = [1], n = [], fs = 1) if nargin == 0 || nargin > 4 print_usage; endif if isempty(n) && length(a) > 1 precision = 1e-6; r = roots(a); maxpole = max(abs(r)); if (maxpole > 1+precision) # unstable -- cutoff at 120 dB n = floor(6/log10(maxpole)); elseif (maxpole < 1-precision) # stable -- cutoff at -120 dB n = floor(-6/log10(maxpole)); else # periodic -- cutoff after 5 cycles n = 30; ## find longest period less than infinity ## cutoff after 5 cycles (w=10*pi) rperiodic = r(find(abs(r)>=1-precision & abs(arg(r))>0)); if !isempty(rperiodic) n_periodic = ceil(10*pi./min(abs(arg(rperiodic)))); if (n_periodic > n) n = n_periodic; endif endif ## find most damped pole ## cutoff at -60 dB rdamped = r(find(abs(r)<1-precision)); if !isempty(rdamped) n_damped = floor(-3/log10(max(abs(rdamped)))); if (n_damped > n) n = n_damped; endif endif endif n = n + length(b); elseif isempty(n) n = length(b); elseif (! isscalar (n)) ## TODO: missing option of having N as a vector of values to ## compute the impulse response. error ("impz: N must be empty or a scalar"); endif if length(a) == 1 x = fftfilt(b/a, [1, zeros(1,n-1)]'); else x = filter(b, a, [1, zeros(1,n-1)]'); endif t = [0:n-1]/fs; if nargout >= 1 x_r = x; endif if nargout >= 2 t_r = t; endif if nargout == 0 unwind_protect title "Impulse Response"; if (fs > 1000) t = t * 1000; xlabel("Time (msec)"); else xlabel("Time (sec)"); endif plot(t, x, "^r;;"); unwind_protect_cleanup title ("") xlabel ("") end_unwind_protect endif endfunction %!assert (size (impz (1, [1 -1 0.9], 100)), [100 1]) ## Missing functionality %!xtest %! [h, t] = impz (1, [1 -1 0.9], 0:101); %! assert (size (h), [101 1]) %! assert (t, 0:101) signal-1.4.5/inst/interp.m0000644000000000000000000000457214456505401013634 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} interp (@var{x}, @var{q}) ## @deftypefnx {Function File} {@var{y} =} interp (@var{x}, @var{q}, @var{n}) ## @deftypefnx {Function File} {@var{y} =} interp (@var{x}, @var{q}, @var{n}, @var{Wc}) ## ## Upsample the signal x by a factor of q, using an order 2*q*n+1 FIR ## filter. Note that q must be an integer for this rate change method. ## n defaults to 4 and Wc defaults to 0.5. ## ## Example ## @example ## @group ## # Generate a signal. ## t=0:0.01:2; x=chirp(t,2,.5,10,'quadratic')+sin(2*pi*t*0.4); ## y = interp(x(1:4:length(x)),4,4,1); # interpolate a sub-sample ## stem(t(1:121)*1000,x(1:121),"-g;Original;"); hold on; ## stem(t(1:121)*1000,y(1:121),"-r;Interpolated;"); ## stem(t(1:4:121)*1000,x(1:4:121),"-b;Subsampled;"); hold off; ## @end group ## @end example ## ## @seealso{decimate, resample} ## @end deftypefn function y = interp(x, q, n = 4, Wc = 0.5) if nargin < 1 || nargin > 4, print_usage; endif if q != fix(q), error("decimate only works with integer q."); endif if rows(x)>1 y = zeros(length(x)*q+q*n+1,1); else y = zeros(1,length(x)*q+q*n+1); endif y(1:q:length(x)*q) = x; b = fir1(2*q*n+1, Wc/q); y=q*fftfilt(b, y); y(1:q*n+1) = []; # adjust for zero filter delay endfunction %!demo %! ## Generate a signal. %! t=0:0.01:2; x=chirp(t,2,.5,10,'quadratic')+sin(2*pi*t*0.4); %! y = interp(x(1:4:length(x)),4,4,1); # interpolate a sub-sample %! plot(t(1:121)*1000,y(1:121),"r-+;Interpolated;"); hold on; %! stem(t(1:4:121)*1000,x(1:4:121),"ob;Original;"); hold off; %! %! % graph shows interpolated signal following through the %! % sample points of the original signal. signal-1.4.5/inst/invfreq.m0000644000000000000000000002161114456505401013776 0ustar0000000000000000## Copyright (C) 1986, 2000, 2003 Julius O. Smith III ## Copyright (C) 2007 Rolf Schirmacher ## Copyright (C) 2003 Andrew Fitting ## Copyright (C) 2010 Pascal Dupuis ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[B,A] =} invfreq(H,F,nB,nA) ## @deftypefnx {} {[B,A] =} invfreq(H,F,nB,nA,W) ## @deftypefnx {} {[B,A] =} invfreq(H,F,nB,nA,W,[],[],plane) ## @deftypefnx {} {[B,A] =} invfreq(H,F,nB,nA,W,iter,tol,plane) ## Fit filter B(z)/A(z) or B(s)/A(s) to complex frequency response at ## frequency points F. ## ## A and B are real polynomial coefficients of order ## nA and nB respectively. Optionally, the fit-errors can be weighted vs ## frequency according to the weights W. Also, the transform plane can be ## specified as either 's' for continuous time or 'z' for discrete time. 'z' ## is chosen by default. Eventually, Steiglitz-McBride iterations will be ## specified by iter and tol. ## ## H: desired complex frequency response ## It is assumed that A and B are real polynomials, hence H is one-sided. ## ## F: vector of frequency samples in radians ## ## nA: order of denominator polynomial A ## ## nB: order of numerator polynomial B ## ## plane='z': F on unit circle (discrete-time spectra, z-plane design) ## ## plane='s': F on jw axis (continuous-time spectra, s-plane design) ## ## H(k) = spectral samples of filter frequency response at points zk, ## where zk=exp(sqrt(-1)*F(k)) when plane='z' (F(k) in [0,.5]) ## and zk=(sqrt(-1)*F(k)) when plane='s' (F(k) nonnegative) ## ## Example: ## @example ## [B,A] = butter(12,1/4); ## [H,w] = freqz(B,A,128); ## [Bh,Ah] = invfreq(H,F,4,4); ## Hh = freqz(Bh,Ah); ## disp(sprintf('||frequency response error|| = %f',norm(H-Hh))); ## @end example ## ## References: ## ## J. O. Smith, "Techniques for Digital Filter Design and System ## Identification with Application to the Violin, Ph.D. Dissertation, ## Elec. Eng. Dept., Stanford University, June 1983, page 50; or, ## ## http://ccrma.stanford.edu/~jos/filters/FFT_Based_Equation_Error_Method.html ## @end deftypefn ## FIXME: implement Steiglitz-McBride iterations ## FIXME: improve numerical stability for high order filters (matlab is a bit better) ## FIXME: modify to accept more argument configurations function [B, A, SigN] = invfreq(H, F, nB, nA, W, iter, tol, tr, plane, varargin) if length(nB) > 1, zB = nB(2); nB = nB(1); else zB = 0; endif n = max(nA, nB); m = n+1; mA = nA+1; mB = nB+1; nF = length(F); if nargin < 5 || isempty(W), W = ones(1, nF); endif if nargin < 6, iter = []; endif if nargin < 7 tol = []; endif if nargin < 8 || isempty(tr), tr = ''; endif if nargin < 9, plane = 'z'; endif if nargin < 10, varargin = {}; endif if (! strcmp (plane, "s") && ! strcmp (plane, "z")) error ("invfreq: invalid PLANE argument '%s', expected 's' or 'z'", plane) endif fname = ["invfreq", plane]; if (nF != length (H)) error ("%s: length of H and F must be the same\n", fname) endif if (! isempty (iter) || ! isempty (tol)) warning (["%s: iterative algorithm not yet implemented, ", ... "ITER and TOL arguments are ignored\n"], fname); endif [reg, prop ] = parseparams(varargin); ## should we normalize freqs to avoid matrices with rank deficiency ? norm = false; ## by default, use Ordinary Least Square to solve normal equations method = 'LS'; if length(prop) > 0 indi = 1; while indi <= length(prop) switch prop{indi} case 'norm' if indi < length(prop) && ~ischar(prop{indi+1}), norm = logical(prop{indi+1}); prop(indi:indi+1) = []; continue else norm = true; prop(indi) = []; continue endif case 'method' if indi < length(prop) && ischar(prop{indi+1}), method = prop{indi+1}; prop(indi:indi+1) = []; continue else error('invfreq.m: incorrect/missing method argument'); endif otherwise # FIXME: just skip it for now disp(sprintf("Ignoring unknown argument %s", varargin{indi})); indi = indi + 1; endswitch endwhile endif Ruu = zeros(mB, mB); Ryy = zeros(nA, nA); Ryu = zeros(nA, mB); Pu = zeros(mB, 1); Py = zeros(nA,1); if strcmp(tr,'trace') disp(' ') disp('Computing nonuniformly sampled, equation-error, rational filter.'); disp(['plane = ',plane]); disp(' ') endif s = sqrt(-1)*F; switch plane case 'z' if max(F) > pi || min(F) < 0 disp('hey, you frequency is outside the range 0 to pi, making my own') F = linspace(0, pi, length(H)); s = sqrt(-1)*F; endif s = exp(-s); case 's' if max(F) > 1e6 && n > 5, if ~norm, disp('Be careful, there are risks of generating singular matrices'); disp('Call invfreqs as (..., "norm", true) to avoid it'); else Fmax = max(F); s = sqrt(-1)*F/Fmax; endif endif endswitch for k=1:nF, Zk = (s(k).^[0:n]).'; Hk = H(k); aHks = Hk*conj(Hk); Rk = (W(k)*Zk)*Zk'; rRk = real(Rk); Ruu = Ruu + rRk(1:mB, 1:mB); Ryy = Ryy + aHks*rRk(2:mA, 2:mA); Ryu = Ryu + real(Hk*Rk(2:mA, 1:mB)); Pu = Pu + W(k)*real(conj(Hk)*Zk(1:mB)); Py = Py + (W(k)*aHks)*real(Zk(2:mA)); endfor Rr = ones(length(s), mB+nA); Zk = s; for k = 1:min(nA, nB), Rr(:, 1+k) = Zk; Rr(:, mB+k) = -Zk.*H; Zk = Zk.*s; endfor for k = 1+min(nA, nB):max(nA, nB)-1, if k <= nB, Rr(:, 1+k) = Zk; endif if k <= nA, Rr(:, mB+k) = -Zk.*H; endif Zk = Zk.*s; endfor k = k+1; if k <= nB, Rr(:, 1+k) = Zk; endif if k <= nA, Rr(:, mB+k) = -Zk.*H; endif ## complex to real equation system -- this ensures real solution Rr = Rr(:, 1+zB:end); Rr = [real(Rr); imag(Rr)]; Pr = [real(H(:)); imag(H(:))]; ## normal equations -- keep for ref ## Rn= [Ruu(1+zB:mB, 1+zB:mB), -Ryu(:, 1+zB:mB)'; -Ryu(:, 1+zB:mB), Ryy]; ## Pn= [Pu(1+zB:mB); -Py]; switch method case {'ls' 'LS'} ## avoid scaling errors with Theta = R\P; ## [Q, R] = qr([Rn Pn]); Theta = R(1:end, 1:end-1)\R(1:end, end); [Q, R] = qr([Rr Pr], 0); Theta = R(1:end-1, 1:end-1)\R(1:end-1, end); ## SigN = R(end, end-1); SigN = R(end, end); case {'tls' 'TLS'} ## [U, S, V] = svd([Rn Pn]); ## SigN = S(end, end-1); ## Theta = -V(1:end-1, end)/V(end, end); [U, S, V] = svd([Rr Pr], 0); SigN = S(end, end); Theta = -V(1:end-1, end)/V(end, end); case {'mls' 'MLS' 'qr' 'QR'} ## [Q, R] = qr([Rn Pn], 0); ## solve the noised part -- DO NOT USE ECONOMY SIZE ! ## [U, S, V] = svd(R(nA+1:end, nA+1:end)); ## SigN = S(end, end-1); ## Theta = -V(1:end-1, end)/V(end, end); ## unnoised part -- remove B contribution and back-substitute ## Theta = [R(1:nA, 1:nA)\(R(1:nA, end) - R(1:nA, nA+1:end-1)*Theta) ## Theta]; ## solve the noised part -- economy size OK as #rows > #columns [Q, R] = qr([Rr Pr], 0); eB = mB-zB; sA = eB+1; [U, S, V] = svd(R(sA:end, sA:end)); ## noised (A) coefficients Theta = -V(1:end-1, end)/V(end, end); ## unnoised (B) part -- remove A contribution and back-substitute Theta = [R(1:eB, 1:eB)\(R(1:eB, end) - R(1:eB, sA:end-1)*Theta) Theta]; SigN = S(end, end); otherwise error("invfreq: unknown method %s", method); endswitch B = [zeros(zB, 1); Theta(1:mB-zB)].'; A = [1; Theta(mB-zB+(1:nA))].'; if strcmp(plane,'s') B = B(mB:-1:1); A = A(mA:-1:1); if norm, # Frequencies were normalized -- unscale coefficients Zk = Fmax.^[n:-1:0].'; for k = nB:-1:1+zB, B(k) = B(k)/Zk(k); endfor for k = nA:-1:1, A(k) = A(k)/Zk(k); endfor endif endif endfunction %!demo %! order = 6; # order of test filter %! fc = 1/2; # sampling rate / 4 %! n = 128; # frequency grid size %! [B, A] = butter(order,fc); %! [H, w] = freqz(B,A,n); %! [Bh, Ah] = invfreq(H,w,order,order); %! [Hh, wh] = freqz(Bh,Ah,n); %! plot(w,[abs(H), abs(Hh)]) %! xlabel("Frequency (rad/sample)"); %! ylabel("Magnitude"); %! legend('Original','Measured'); %! err = norm(H-Hh); %! disp(sprintf('L2 norm of frequency response error = %f',err)); signal-1.4.5/inst/invfreqs.m0000644000000000000000000000651614456505401014170 0ustar0000000000000000## Copyright (C) 1986, 2003 Julius O. Smith III ## Copyright (C) 2003 Andrew Fitting ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[B,A] =} invfreqs(H,F,nB,nA) ## @deftypefnx {} {[B,A] =} invfreqs(H,F,nB,nA,W) ## @deftypefnx {} {[B,A] =} invfreqs(H,F,nB,nA,W,iter,tol,'trace') ## Fit filter B(s)/A(s)to the complex frequency response H at frequency ## points F. ## ## A and B are real polynomial coefficients of order nA and nB. ## ## Optionally, the fit-errors can be weighted vs frequency according to ## the weights W. ## ## Note: all the guts are in invfreq.m ## ## H: desired complex frequency response ## ## F: frequency (must be same length as H) ## ## nA: order of the denominator polynomial A ## ## nB: order of the numerator polynomial B ## ## W: vector of weights (must be same length as F) ## ## Example: ## @example ## B = [1/2 1]; ## A = [1 1]; ## w = linspace(0,4,128); ## H = freqs(B,A,w); ## [Bh,Ah] = invfreqs(H,w,1,1); ## Hh = freqs(Bh,Ah,w); ## plot(w,[abs(H);abs(Hh)]) ## legend('Original','Measured'); ## err = norm(H-Hh); ## disp(sprintf('L2 norm of frequency response error = %f',err)); ## @end example ## @end deftypefn ## FIXME: check invfreq.m for todo's function [B, A, SigN] = invfreqs(H,F,nB,nA,W,iter,tol,tr, varargin) if nargin < 9 varargin = {}; if nargin < 8 tr = ''; if nargin < 7 tol = []; if nargin < 6 iter = []; if nargin < 5 W = ones(1,length(F)); endif endif endif endif endif ## now for the real work [B, A, SigN] = invfreq(H, F,nB, nA, W, iter, tol, tr, 's', varargin{:}); endfunction %!demo %! B = [1/2 1]; %! B = [1 0 0]; %! A = [1 1]; %! ##A = [1 36 630 6930 51975 270270 945945 2027025 2027025]/2027025; %! A = [1 21 210 1260 4725 10395 10395]/10395; %! A = [1 6 15 15]/15; %! w = linspace(0, 8, 128); %! H0 = freqs(B, A, w); %! Nn = (randn(size(w))+j*randn(size(w)))/sqrt(2); %! order = length(A) - 1; %! [Bh, Ah, Sig0] = invfreqs(H0, w, [length(B)-1 2], length(A)-1); %! Hh = freqs(Bh,Ah,w); %! [BLS, ALS, SigLS] = invfreqs(H0+1e-5*Nn, w, [2 2], order, [], [], [], [], "method", "LS"); %! HLS = freqs(BLS, ALS, w); %! [BTLS, ATLS, SigTLS] = invfreqs(H0+1e-5*Nn, w, [2 2], order, [], [], [], [], "method", "TLS"); %! HTLS = freqs(BTLS, ATLS, w); %! [BMLS, AMLS, SigMLS] = invfreqs(H0+1e-5*Nn, w, [2 2], order, [], [], [], [], "method", "QR"); %! HMLS = freqs(BMLS, AMLS, w); %! plot(w,[abs(H0); abs(Hh)]) %! xlabel("Frequency (rad/sec)"); %! ylabel("Magnitude"); %! legend('Original','Measured'); %! err = norm(H0-Hh); %! disp(sprintf('L2 norm of frequency response error = %f',err)); signal-1.4.5/inst/invfreqz.m0000644000000000000000000000627314456505401014177 0ustar0000000000000000## Copyright (C) 1986, 2003 Julius O. Smith III ## Copyright (C) 2003 Andrew Fitting ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[B,A] =} invfreqz(H,F,nB,nA) ## @deftypefnx {} {[B,A] =} invfreqz(H,F,nB,nA,W) ## @deftypefnx {} {[B,A] =} invfreqz(H,F,nB,nA,W,iter,tol,'trace') ## Fit filter B(z)/A(z)to the complex frequency response H at frequency ## points F. ## ## A and B are real polynomial coefficients of order nA and nB. ## Optionally, the fit-errors can be weighted vs frequency according to ## the weights W. ## ## Note: all the guts are in invfreq.m ## ## H: desired complex frequency response ## ## F: normalized frequency (0 to pi) (must be same length as H) ## ## nA: order of the denominator polynomial A ## ## nB: order of the numerator polynomial B ## ## W: vector of weights (must be same length as F) ## ## Example: ## @example ## [B,A] = butter(4,1/4); ## [H,F] = freqz(B,A); ## [Bh,Ah] = invfreq(H,F,4,4); ## Hh = freqz(Bh,Ah); ## disp(sprintf('||frequency response error|| = %f',norm(H-Hh))); ## @end example ## @end deftypefn ## FIXME: check invfreq.m for todo's function [B, A, SigN] = invfreqz(H, F, nB, nA, W, iter, tol, tr, varargin) if nargin < 9 varargin = {}; if nargin < 8 tr = ''; if nargin < 7 tol = []; if nargin < 6 iter = []; if nargin < 5 W = ones(1,length(F)); endif endif endif endif endif ## now for the real work [B, A, SigN] = invfreq(H, F, nB, nA, W, iter, tol, tr, 'z', varargin{:}); endfunction %!demo %! order = 9; # order of test filter %! # going to 10 or above leads to numerical instabilities and large errors %! fc = 1/2; # sampling rate / 4 %! n = 128; # frequency grid size %! [B0, A0] = butter(order, fc); %! [H0, w] = freqz(B0, A0, n); %! Nn = (randn(size(w))+j*randn(size(w)))/sqrt(2); %! [Bh, Ah, Sig0] = invfreqz(H0, w, order, order); %! [Hh, wh] = freqz(Bh, Ah, n); %! [BLS, ALS, SigLS] = invfreqz(H0+1e-5*Nn, w, order, order, [], [], [], [], "method", "LS"); %! HLS = freqz(BLS, ALS, n); %! [BTLS, ATLS, SigTLS] = invfreqz(H0+1e-5*Nn, w, order, order, [], [], [], [], "method", "TLS"); %! HTLS = freqz(BTLS, ATLS, n); %! [BMLS, AMLS, SigMLS] = invfreqz(H0+1e-5*Nn, w, order, order, [], [], [], [], "method", "QR"); %! HMLS = freqz(BMLS, AMLS, n); %! plot(w,[abs(H0) abs(Hh)]) %! xlabel("Frequency (rad/sample)"); %! ylabel("Magnitude"); %! legend('Original','Measured'); %! err = norm(H0-Hh); %! disp(sprintf('L2 norm of frequency response error = %f',err)); signal-1.4.5/inst/invimpinvar.m0000644000000000000000000001265714456505401014700 0ustar0000000000000000## Copyright (C) 2007 R.G.H. Eschauzier ## Copyright (C) 2011 CarnĂ« Draug ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{b_out}, @var{a_out}] =} invimpinvar (@var{b}, @var{a}, @var{fs}, @var{tol}) ## @deftypefnx {Function File} {[@var{b_out}, @var{a_out}] =} invimpinvar (@var{b}, @var{a}, @var{fs}) ## @deftypefnx {Function File} {[@var{b_out}, @var{a_out}] =} invimpinvar (@var{b}, @var{a}) ## Converts digital filter with coefficients @var{b} and @var{a} to analog, ## conserving impulse response. ## ## This function does the inverse of impinvar so that the following example should ## restore the original values of @var{a} and @var{b}. ## @example ## [b, a] = impinvar (b, a); ## [b, a] = invimpinvar (b, a); ## @end example ## ## If @var{fs} is not specified, or is an empty vector, it defaults to 1Hz. ## ## If @var{tol} is not specified, it defaults to 0.0001 (0.1%) ## ## Reference: Thomas J. Cavicchi (1996) ``Impulse invariance and multiple-order ## poles''. IEEE transactions on signal processing, Vol 40 (9): 2344--2347 ## ## @seealso{bilinear, impinvar} ## @end deftypefn ## Impulse invariant conversion from s to z domain function [b_out, a_out] = invimpinvar (b_in, a_in, fs = 1, tol = 0.0001) if (nargin <2) print_usage; endif ## to be compatible with the matlab implementation where an empty vector can ## be used to get the default if (isempty(fs)) ts = 1; else ts = 1/fs; # we should be using sampling frequencies to be compatible with Matlab endif b_in = [b_in 0]; # so we can calculate in z instead of z^-1 [r_in, p_in, k_in] = residue(b_in, a_in); # partial fraction expansion n = length(r_in); # Number of poles/residues if (length(k_in) > 1) # Greater than one means we cannot do impulse invariance error("Order numerator > order denominator"); endif r_out = zeros(1,n); # Residues of H(s) sm_out = zeros(1,n); # Poles of H(s) i=1; while (i<=n) m=1; first_pole = p_in(i); # Pole in the z-domain while (i1) # Go through residues starting from highest order down r_out(j) = r_in(j) / ((ts * p_in)^j); # Back to binomial coefficient for highest order (always 1) r_in(1:j) -= r_out(j) * polyrev(h1_z_deriv(j-1,p_in,ts)); # Subtract highest order result, leaving r_in(j) zero j--; endwhile ## Single pole (no multiplicity) r_out(1) = r_in(1) / ((ts * p_in)); k_out = r_in(1) / p_in; sm_out = log(p_in) / ts; endfunction %!function err = ztoserr(bz,az,fs) %! %! # number of time steps %! n=100; %! %! # make sure system is realizable (no delays) %! bz=prepad(bz,length(az)-1,0,2); %! %! # inverse impulse invariant transform to s-domain %! [bs as]=invimpinvar(bz,az,fs); %! %! # create sys object of transfer function %! s=tf(bs,as); %! %! # calculate impulse response of continuous time system %! # at discrete time intervals 1/fs %! ys=impulse(s,(n-1)/fs,1/fs)'; %! %! # impulse response of discrete time system %! yz=filter(bz,az,[1 zeros(1,n-1)]); %! %! # find rms error %! err=sqrt(sum((yz*fs-ys).^2)/length(ys)); %! endfunction %! %!assert(ztoserr([1],[1 -0.5],0.01),0,0.0001); %!assert(ztoserr([1],[1 -1 0.25],0.01),0,0.0001); %!assert(ztoserr([1 1],[1 -1 0.25],0.01),0,0.0001); %!assert(ztoserr([1],[1 -1.5 0.75 -0.125],0.01),0,0.0001); %!assert(ztoserr([1 1],[1 -1.5 0.75 -0.125],0.01),0,0.0001); %!assert(ztoserr([1 1 1],[1 -1.5 0.75 -0.125],0.01),0,0.0001); %!assert(ztoserr([1],[1 0 0.25],0.01),0,0.0001); %!assert(ztoserr([1 1],[1 0 0.25],0.01),0,0.0001); %!assert(ztoserr([1],[1 0 0.5 0 0.0625],0.01),0,0.0001); %!assert(ztoserr([1 1],[1 0 0.5 0 0.0625],0.01),0,0.0001); %!assert(ztoserr([1 1 1],[1 0 0.5 0 0.0625],0.01),0,0.0001); %!assert(ztoserr([1 1 1 1],[1 0 0.5 0 0.0625],0.01),0,0.0001); signal-1.4.5/inst/isallpass.m0000644000000000000000000000676114456505401014330 0ustar0000000000000000## Copyright (C) 2023 Leonardo Araujo ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{L} = } isallpass (@var{b}, @var{a}) ## @deftypefnx {Function File} {@var{L} = } isallpass (@var{sos}) ## ## Determine whether a digital filter is allpass. The filter might be defined ## by the numerator coefficients, @var{b}, and the denominator coefficients, ## @var{a}, or, alternatively, by a matrix of second-order sections, @var{sos}. ## ## Example: ## @example ## a = [1 2 3]; ## b = [3 2 1]; ## isallpass (b, a) ## @end example ## ## Ref [1] Shyu, Jong-Jy, & Pei, Soo-Chang, ## A new approach to the design of complex all-pass IIR digital filters, ## Signal Processing, 40(2–3), 207–215, 1994. ## https://doi.org/10.1016/0165-1684(94)90068-x ## ## Ref [2] Vaidyanathan, P. P. Multirate Systems and Filter Banks. ## 1st edition, Pearson College Div, 1992. ## @end deftypefn function flag = isallpass (b, a) if (nargin < 1 || nargin > 2 ) print_usage; endif if (nargin == 2 && ( ! isrow (a) || ! isrow (b) )) error ( "coefficient array should be a row vector" ); endif if (nargin == 1 && ! all(size (b) > [1 1]) ) error ( "a valid second-order section representation should be given" ); endif if nargin == 2 && !all(size (b) == size (a)), flag = false; return; elseif (nargin == 2 && isrow (a) && isrow (b)) # remove leading and trailing zeros b = b(find (b, 1):end); a = a(find (a, 1):end); b = b(1:find (b,1,"last")); a = a(1:find (a,1,"last")); # normalize b = b./b(end); a = a./a(1); flag = (all(b == fliplr (conj(a))) || all(b == -fliplr (conj(a)))); elseif (nargin == 1 && all(size (b) > [1 1])) [b, a] = sos2tf (b); flag = isallpass (b, a); endif endfunction %!demo %! # H(z) = (b1 - z^-1) * (b2 - z^-1) / ((1 - b1*z^-1) * (1 - b2*z^-1)) %! b1 = 0.5 * (1 + i); %! b2 = 0.7 * (cos (pi/6) + i*sin (pi/6)); %! b = conv ([b1 -1], [b2 -1]); %! a = conv ([1 (-1)*conj(b1)],[1 (-1)*conj(b2)]); %! freqz (b, a); %! f = isallpass (b, a) %! ## test input validation %!error n = isallpass () %!error n = isallpass (1) %!error n = isallpass (1, 1, 1) %!error n = isallpass (1, 1, 1, 1) %!error n = isallpass (1, 1, 1, 1, 1) %!error n = isallpass ([1:10]', 1) %!error n = isallpass (1, [1:10]') %!error n = isallpass ([1:10]', [1:10]') %!error n = isallpass (1:10, 1:10, 1:10) %!error n = isallpass (ones (3), ones (3)) %!test %! b = [(1+i)/2 -1]; %! a = [1 -(1-i)/2]; %! f = isallpass (b, a); %! assert (f, true) %!test %! b = [(1+i)/2 -1]; %! a = [-1 (1-i)/2]; %! f = isallpass (b, a); %! assert (f, true) %!test %! [b, a] = butter (1, 0.5); %! f = isallpass (b, a); %! assert (f, false) %!test %! b1 = 0.5 * (1 + i); %! b2 = 0.7 * (cos (pi/6) + i*sin (pi/6)); %! b = conv ([b1 -1], [b2 -1]); %! a = conv ([1 -conj(b1)],[1, -conj(b2)]); %! f = isallpass (b, a); %! assert (f, true) signal-1.4.5/inst/ismaxphase.m0000644000000000000000000000731214456505401014470 0ustar0000000000000000## Copyright (C) 2023 Leonardo Araujo ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{L} = } ismaxphase (@var{b}, @var{a}) ## @deftypefnx {Function File} {@var{L} = } ismaxphase (@var{sos}) ## @deftypefnx {Function File} {@var{L} = } ismaxphase (@dots{}, @var{tol}) ## ## Determine whether a digital filter is maximum phase (maximum energy-delay). ## The filter might be defined by the numerator coefficients, @var{b}, and the ## denominator coefficients, @var{a}, or, alternatively, by a matrix of ## second-order sections, @var{sos}. A tolerance @var{tol} might be given to ## define when two numbers are close enough to be considered equal. ## ## Example: ## @example ## b = [1 2 4 4 2 1]; ## zplane (b); ## ismaxphase (b) ## @end example ## ## Ref [1] Oppenheim, Alan, and Ronald Schafer. Discrete-Time Signal Processing. ## 3rd edition, Pearson, 2009. ## @end deftypefn function flag = ismaxphase (b, a, tol) if (nargin < 1 || nargin > 3 ) print_usage; endif if (nargin == 2 && ( ! isrow (a) || ! isrow (b) )) error ( "coefficient array should be a row vector" ); endif if (nargin == 1 && isrow (b)) a = 1; endif if nargin < 3 tol = eps^(3/4); elseif length (tol) > 1 error ( "a scalar is expected as the tolerance value" ); endif if (nargin > 1 && isrow (a) && isrow (b)) || (nargin == 1 && isrow (b)) zm = abs (roots (b)); pm = abs (roots (a)); # Zeros of a maximum phase filter are constrained to lie outside the unit circle. # The filter should be stable (poles inside the unit circle). flag = (all (zm > 1 + tol) || isempty (zm)) && (all (pm < 1 - tol) || isempty (pm)); elseif (nargin == 1 && all(size (b) > [1 1])) [b, a] = sos2tf (b); flag = ismaxphase (b, a, tol); endif endfunction %!demo %! [b, a] = butter (1, .5); %! f = ismaxphase (b, a) ## test input validation %!error n = ismaxphase () %!error n = ismaxphase (1, 1, 1, 1) %!error n = ismaxphase (1, 1, 1, 1, 1) %!error n = ismaxphase ([1:10]', 1) %!error n = ismaxphase (1, [1:10]') %!error n = ismaxphase ([1:10]', [1:10]') %!error n = ismaxphase (1:10, 1:10, 1:10) %!error n = ismaxphase (ones (3), ones (3)) %!test %! z1 = [0.9*exp(j*0.6*pi), 0.9*exp(-j*0.6*pi)]; %! z2 = [0.8*exp(j*0.8*pi), 0.8*exp(-j*0.8*pi)]; %! b = poly ([z1 z2]); %! a = 1; %! f = ismaxphase (b, a); %! assert (f, false) %!test %! z1 = [0.9*exp(j*0.6*pi), 0.9*exp(-j*0.6*pi)]; %! z2 = [0.8*exp(j*0.8*pi), 0.8*exp(-j*0.8*pi)]; %! b = poly ([1./z1 1./z2]); %! a = 1; %! f = ismaxphase (b, a); %! assert (f, true) %!test %! z1 = [0.9*exp(j*0.6*pi), 0.9*exp(-j*0.6*pi)]; %! z2 = [0.8*exp(j*0.8*pi), 0.8*exp(-j*0.8*pi)]; %! b = poly ([z1 1./z2]); %! a = 1; %! f = ismaxphase (b, a); %! assert (f, false) %!test %! z1 = [0.9*exp(j*0.6*pi), 0.9*exp(-j*0.6*pi)]; %! z2 = [0.8*exp(j*0.8*pi), 0.8*exp(-j*0.8*pi)]; %! b = poly ([1./z1 z2]); %! a = 1; %! f = ismaxphase (b, a); %! assert (f, false) %!test %! [b, a] = butter (1, .5); %! f = ismaxphase (b, a); %! assert (f, false) %!test %! [b, a] = butter (8, .5); %! f = ismaxphase (b, a); %! assert (f, false) signal-1.4.5/inst/isminphase.m0000644000000000000000000000605614456505401014472 0ustar0000000000000000## Copyright (C) 2023 Leonardo Araujo ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{L} = } isminphase (@var{b}, @var{a}) ## @deftypefnx {Function File} {@var{L} = } isminphase (@var{sos}) ## @deftypefnx {Function File} {@var{L} = } isminphase (@dots{}, @var{tol}) ## ## Determine whether a digital filter is minimum phase. The filter might be defined ## by the numerator coefficients, @var{b}, and the denominator coefficients, ## @var{a}, or, alternatively, by a matrix of second-order sections, @var{sos}. ## A toleranve @var{tol} might be given to define when two numbers are close enough ## to be considered equal. ## ## Example: ## @example ## a = [1 0.5]; b = [3 1]; ## isminphase (b, a) ## @end example ## ## Ref [1] Oppenheim, Alan, and Ronald Schafer. Discrete-Time Signal Processing. ## 3rd edition, Pearson, 2009. ## @end deftypefn function flag = isminphase (b, a, tol) if (nargin < 1 || nargin > 3 || (nargin == 2 && !isrow (b)) || (length (a) > 1 && ! isrow (a)) || (length (b) > 1 && ! isrow (b)) || (nargin == 3 && ! isscalar (tol)) ) print_usage; endif if (nargin == 2 && ! isrow (b)) tol = a; endif if (nargin == 1 && isrow (b)) a = 1; endif if nargin < 3 tol = eps^(3/4); endif if (nargin == 2 && isrow (a) && isrow (b)) || (nargin == 1 && isrow (b)) zm = abs (roots (b)); pm = abs (roots (a)); flag = (all (zm < 1 - tol) || isempty (zm)) && (all (pm < 1 - tol) || isempty (pm)); elseif (nargin == 1 && all(size (b) > [1 1])) [b, a] = sos2tf (b); flag = isminphase (b, a, tol); endif endfunction %!demo %! b = [3 1]; %! a = [1 .5]; %! f = isminphase (b, a) %! ## test input validation %!error n = isminphase () %!error n = isminphase (1, 1, 1, 1) %!error n = isminphase (1, 1, 1, 1, 1) %!error n = isminphase ([1:10]', 1) %!error n = isminphase (1, [1:10]') %!error n = isminphase ([1:10]', [1:10]') %!error n = isminphase (1:10, 1:10, 1:10) %!error n = isminphase (ones (3), ones (3)) %!test %! b = [3 1]; %! a = [1 .5]; %! f = isminphase (b, a); %! assert (f, true) %!test %! [b, a] = butter (1, .5); %! f = isminphase (b, a); %! assert (f, false) %!test %! [b, a] = butter (8, .5); %! f = isminphase (b, a); %! assert (f, false) %!test %! b = 1.25^2 * conv (conv (conv ([1 -0.9*e^(-j*0.6*pi)], [1 -0.9*e^(j*0.6*pi)]), [1 -0.8*e^(-j*0.8*pi)]), [1 -0.8*e^(j*0.8*pi)]); %! a = 1; %! f = isminphase (b, a); %! assert (f, true) signal-1.4.5/inst/isstable.m0000644000000000000000000000527414456505401014141 0ustar0000000000000000## Copyright (C) 2022 The Octave Project Developers ## Copyright (C) 2017 Vasilis Lefkopoulos ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{FLAG} =} isstable (@var{B}, @var{A}) ## Returns a logical output equal to TRUE, if the filter is stable. ## This can be done with coeffients of the filer @var{B} and @var{A}. ## Alternatively by using a second order sections matrix (SOS). ## ## Inputs: ## @itemize ## @item ## @var{B}: Numerator coefficients of the filter ## ## @item ## @var{A}: Denominator coeffients of the filter. Can be an empty vector. ## @end itemize ## ## Output: ## @itemize ## @item ## @var{FLAG}: Returns a logical output, equal to TRUE if the filter is stable. ## @end itemize ## ## Examples: ## @example ## b = [1 2 3 4 5 5 1 2]; ## a = [4 5 6 7 9 10 4 6]; ## flag = isstable (b, a) ## flag = 0 ## @end example ## ## Using SOS ## @example ## [z, p, k] = butter (6, 0.7, 'high'); ## sos = zp2sos (z, p, k); ## flag = isstable (sos) ## flag = 1 ## @end example ## @end deftypefn function flag = isstable (b, varargin) if isempty (varargin) # Only one argument was given if any(size (b) > [1 1]) # A matrix was given and is converted to vectors b & a [b, a] = sos2tf (b); else # Second input vector was omitted a = 1; endif else a = varargin{1}; endif if isempty (a) || (length (a) == 1) # An FIR filter is always stable flag = true; else if (a(1) != 1) # Normalization, so that a(1) equals 1 b = b ./ a(1); a = a ./ a(1); endif r = roots (a); if any (abs (r) > 1) flag = false; else flag = true; endif endif endfunction %!test %! b = [1 2 3 4 5 5 1 2]; %! a = []; %! assert (isstable (b,a), true) %!test %! b = [1 2 3 4 5 5 1 2]; %! a = [4 5 6 7 9 10 4 6]; %! assert (isstable (b,a), false) %!test %! b = [1 2 3 4 5 5 1 2]; %! a = [4 5 6 7 9 10 4 6]; %! a = polystab(a); %! assert (isstable (b,a), true) %!test %! [z,p,g] = butter(6,0.7,'high'); %! sos = zp2sos(z,p,g); %! assert (isstable(sos) , true) signal-1.4.5/inst/kaiser.m0000644000000000000000000000431314456505401013602 0ustar0000000000000000## Copyright (C) 1995, 1996, 1997 Kurt Hornik ## Copyright (C) 2000 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} kaiser (@var{m}) ## @deftypefnx {Function File} {} kaiser (@var{m}, @var{beta}) ## ## Return the filter coefficients of a Kaiser window of length @var{m}. The ## Fourier transform of the window has a stop-band attenuation that is derived ## from the parameter @var{beta}. ## ## For the definition of the Kaiser window, see A. V. Oppenheim & ## R. W. Schafer, "Discrete-Time Signal Processing". ## ## The continuous version of width m centered about x=0 is: ## ## @example ## @group ## besseli(0, beta * sqrt(1-(2*x/m).^2)) ## k(x) = -------------------------------------, m/2 <= x <= m/2 ## besseli(0, beta) ## @end group ## @end example ## ## @seealso{kaiserord} ## @end deftypefn function w = kaiser (m, beta = 0.5) if (nargin < 1 || nargin > 2) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("kaiser: M must be a positive integer"); elseif (! (isscalar (beta) && isreal (beta))) error ("kaiser: BETA must be a real scalar"); endif if (m == 1) w = 1; else N = m - 1; k = (0 : N)'; k = 2 * beta / N * sqrt (k .* (N - k)); w = besseli (0, k) / besseli (0, beta); endif endfunction %!demo %! % use demo("kaiserord"); %!assert (kaiser (1), 1) %% Test input validation %!error kaiser () %!error kaiser (0.5) %!error kaiser (-1) %!error kaiser (ones (1, 4)) %!error kaiser (1, 2, 3) signal-1.4.5/inst/kaiserord.m0000644000000000000000000001341014456505401014305 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{n}, @var{Wn}, @var{beta}, @var{ftype}] =} kaiserord (@var{f}, @var{m}, @var{dev}) ## @deftypefnx {Function File} {[@dots{}] =} kaiserord (@var{f}, @var{m}, @var{dev}, @var{fs}) ## ## Return the parameters needed to produce a filter of the desired ## specification from a Kaiser window. The vector @var{f} contains pairs of ## frequency band edges in the range [0,1]. The vector @var{m} specifies the ## magnitude response for each band. The values of @var{m} must be zero for ## all stop bands and must have the same magnitude for all pass bands. The ## deviation of the filter @var{dev} can be specified as a scalar or a vector ## of the same length as @var{m}. The optional sampling rate @var{fs} can be ## used to indicate that @var{f} is in Hz in the range [0,@var{fs}/2]. ## ## The returned value @var{n} is the required order of the filter (the length ## of the filter minus 1). The vector @var{Wn} contains the band edges of ## the filter suitable for passing to @code{fir1}. The value @var{beta} is ## the parameter of the Kaiser window of length @var{n}+1 to shape the filter. ## The string @var{ftype} contains the type of filter to specify to ## @code{fir1}. ## ## The Kaiser window parameters n and beta are computed from the ## relation between ripple (A=-20*log10(dev)) and transition width ## (dw in radians) discovered empirically by Kaiser: ## ## @example ## @group ## / 0.1102(A-8.7) A > 50 ## beta = | 0.5842(A-21)^0.4 + 0.07886(A-21) 21 <= A <= 50 ## \ 0.0 A < 21 ## ## n = (A-8)/(2.285 dw) ## @end group ## @end example ## ## Example: ## @example ## @group ## [n, w, beta, ftype] = kaiserord ([1000, 1200], [1, 0], [0.05, 0.05], 11025); ## b = fir1 (n, w, kaiser (n+1, beta), ftype, "noscale"); ## freqz (b, 1, [], 11025); ## @end group ## @end example ## @seealso{fir1, kaiser} ## @end deftypefn ## FIXME: order is underestimated for the final test case: 2 stop bands. function [n, w, beta, ftype] = kaiserord(f, m, dev, fs) if (nargin<2 || nargin>4) print_usage; endif ## default sampling rate parameter if nargin<4, fs=2; endif ## parameter checking if length(f)!=2*length(m)-2 error("kaiserord must have one magnitude for each frequency band"); endif if any(m(1:length(m)-2)!=m(3:length(m))) error("kaiserord pass and stop bands must be strictly alternating"); endif if length(dev)!=length(m) && length(dev)!=1 error("kaiserord must have one deviation for each frequency band"); endif dev = min(dev); if dev <= 0, error("kaiserord must have dev>0"); endif ## use midpoints of the transition region for band edges w = (f(1:2:length(f))+f(2:2:length(f)))/fs; ## determine ftype if length(w) == 1 if m(1)>m(2), ftype='low'; else ftype='high'; endif elseif length(w) == 2 if m(1)>m(2), ftype='stop'; else ftype='pass'; endif else if m(1)>m(2), ftype='DC-1'; else ftype='DC-0'; endif endif ## compute beta from dev A = -20*log10(dev); if (A > 50) beta = 0.1102*(A-8.7); elseif (A >= 21) beta = 0.5842*(A-21)^0.4 + 0.07886*(A-21); else beta = 0.0; endif ## compute n from beta and dev dw = 2*pi*min(f(2:2:length(f))-f(1:2:length(f)))/fs; n = max(1,ceil((A-8)/(2.285*dw))); ## if last band is high, make sure the order of the filter is even. if ((m(1)>m(2)) == (rem(length(w),2)==0)) && rem(n,2)==1, n = n+1; endif endfunction %!demo %! Fs = 11025; %! for i=1:4 %! if i==1, %! subplot(221); bands=[1200, 1500]; mag=[1, 0]; dev=[0.1, 0.1]; %! elseif i==2 %! subplot(222); bands=[1000, 1500]; mag=[0, 1]; dev=[0.1, 0.1]; %! elseif i==3 %! subplot(223); bands=[1000, 1200, 3000, 3500]; mag=[0, 1, 0]; dev=0.1; %! elseif i==4 %! subplot(224); bands=100*[10, 13, 15, 20, 30, 33, 35, 40]; %! mag=[1, 0, 1, 0, 1]; dev=0.05; %! endif %! [n, w, beta, ftype] = kaiserord(bands, mag, dev, Fs); %! d=max(1,fix(n/10)); %! if mag(length(mag))==1 && rem(d,2)==1, d=d+1; endif %! [h, f] = freqz(fir1(n,w,ftype,kaiser(n+1,beta),'noscale'),1,[],Fs); %! hm = freqz(fir1(n-d,w,ftype,kaiser(n-d+1,beta),'noscale'),1,[],Fs); %! plot(f,abs(hm),sprintf("r;order %d;",n-d), ... %! f,abs(h), sprintf("b;order %d;",n)); %! b = [0, bands, Fs/2]; hold on; %! for i=2:2:length(b), %! hi=mag(i/2)+dev(1); lo=max(mag(i/2)-dev(1),0); %! plot([b(i-1), b(i), b(i), b(i-1), b(i-1)],[hi, hi, lo, lo, hi],"c;;"); %! endfor; hold off; %! endfor %! %! %-------------------------------------------------------------- %! % A filter meets the specifications if its frequency response %! % passes through the ends of the criteria boxes, and fails if %! % it passes through the top or the bottom. The criteria are %! % met precisely if the frequency response only passes through %! % the corners of the boxes. The blue line is the filter order %! % returned by kaiserord, and the red line is some lower filter %! % order. Confirm that the blue filter meets the criteria and %! % the red line fails. ## FIXME: extend demo to show detail at criteria box corners signal-1.4.5/inst/levinson.m0000644000000000000000000000644114456505401014165 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{a}, @var{v}, @var{ref}] =} levinson (@var{acf}) ## @deftypefnx {Function File} {[@dots{}] =} levinson (@var{acf}, @var{p}) ## ## Use the Durbin-Levinson algorithm to solve: ## toeplitz(acf(1:p)) * x = -acf(2:p+1). ## The solution [1, x'] is the denominator of an all pole filter ## approximation to the signal x which generated the autocorrelation ## function acf. ## ## acf is the autocorrelation function for lags 0 to p. ## p defaults to length(acf)-1. ## Returns ## a=[1, x'] the denominator filter coefficients. ## v= variance of the white noise = square of the numerator constant ## ref = reflection coefficients = coefficients of the lattice ## implementation of the filter ## Use freqz(sqrt(v),a) to plot the power spectrum. ## ## REFERENCE ## [1] Steven M. Kay and Stanley Lawrence Marple Jr.: ## "Spectrum analysis -- a modern perspective", ## Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981 ## @end deftypefn ## Based on: ## yulewalker.m ## Copyright (C) 1995 Friedrich Leisch ## GPL license ## FIXME: Matlab doesn't return reflection coefficients and ## errors in addition to the polynomial a. ## FIXME: What is the difference between aryule, levinson, ## ac2poly, ac2ar, lpc, etc.? function [a, v, ref] = levinson (acf, p) if ( nargin<1 ) print_usage; elseif( ~isvector(acf) || length(acf)<2 ) error( "levinson: arg 1 (acf) must be vector of length >1\n"); elseif ( nargin>1 && ( ~isscalar(p) || fix(p)~=p ) ) error( "levinson: arg 2 (p) must be integer >0\n"); else if ((nargin == 1)||(p>=length(acf))) p = length(acf) - 1; endif if( columns(acf)>1 ) acf=acf(:); endif # force a column vector if nargout < 3 && p < 100 ## direct solution [O(p^3), but no loops so slightly faster for small p] ## Kay & Marple Eqn (2.39) R = toeplitz(acf(1:p), conj(acf(1:p))); a = R \ -acf(2:p+1); a = [ 1, a.' ]; v = real( a*conj(acf(1:p+1)) ); else ## durbin-levinson [O(p^2), so significantly faster for large p] ## Kay & Marple Eqns (2.42-2.46) ref = zeros(p,1); g = -acf(2)/acf(1); a = [ g ]; v = real( ( 1 - g*conj(g)) * acf(1) ); ref(1) = g; for t = 2 : p g = -(acf(t+1) + a * acf(t:-1:2)) / v; a = [ a+g*conj(a(t-1:-1:1)), g ]; v = v * ( 1 - real(g*conj(g)) ) ; ref(t) = g; endfor a = [1, a]; endif endif endfunction signal-1.4.5/inst/lpc.m0000644000000000000000000001033414456505401013102 0ustar0000000000000000## Copyright (C) 2013 Leonardo Araujo ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{a} = } lpc (@var{x}) ## @deftypefnx {Function File} {@var{a} = } lpc (@var{x}, @var{p}) ## @deftypefnx {Function File} {[@var{a}, @var{g}] = } lpc (@dots{}) ## @deftypefnx {Function File} {[@var{a}, @var{g}] = } lpc (@var{x}, @var{p}) ## ## Determines the forward linear predictor by minimizing the prediction error ## in the least squares sense. Use the Durbin-Levinson algorithm to solve ## the Yule-Walker equations obtained by the autocorrelation of the input ## signal. ## ## @var{x} is a data vector used to estimate the lpc model of @var{p}-th order, ## given by the prediction polynomial @code{@var{a} = [1 @var{a}(2) @dots{} ## @var{a}(@var{p}+1)]}. If @var{p} is not provided, @code{length(@var{p}) - 1} ## is used as default. ## ## @var{x} might also be a matrix, in which case each column is regarded as a ## separate signal. @code{lpc} will return a model estimate for each column of ## @var{x}. ## ## @var{g} is the variance (power) of the prediction error for each signal in ## @var{x}. ## ## @seealso{aryule,levinson} ## @end deftypefn function [a, g] = lpc (x, p) if (nargin < 1 || nargin > 2) print_usage; elseif (! isrow (x) && rows (x) < 2) error( "lpc: rows(X) must be >1" ); elseif (nargin == 2 && (! isscalar (p) || fix (p) != p || p > length (x) - 1 || p < 1)) error( "lpc: P must be an integer >0 and ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{q} =} marcumq (@var{a}, @var{b}) ## @deftypefnx {Function File} {@var{q} =} marcumq (@var{a}, @var{b}, @var{m}) ## @deftypefnx {Function File} {@var{q} =} marcumq (@var{a}, @var{b}, @var{m}, @var{tol}) ## ## Compute the generalized Marcum Q function of order @var{m} with ## noncentrality parameter @var{a} and argument @var{b}. If the order ## @var{m} is omitted it defaults to 1. An optional relative tolerance ## @var{tol} may be included, the default is @code{eps}. ## ## If the input arguments are commensurate vectors, this function ## will produce a table of values. ## ## This function computes Marcum's Q function using the infinite ## Bessel series, truncated when the relative error is less than ## the specified tolerance. The accuracy is limited by that of ## the Bessel functions, so reducing the tolerance is probably ## not useful. ## ## Reference: Marcum, "Tables of Q Functions", Rand Corporation. ## ## Reference: R.T. Short, "Computation of Noncentral Chi-squared ## and Rice Random Variables", www.phaselockedsystems.com/publications ## ## @end deftypefn function q = marcumq (a, b, m = 1, tol = eps) if ((nargin < 2) || (nargin > 4)) print_usage (); endif if (any (a < 0)) error ("marcumq: A must be a non-negative value"); endif if (any (b < 0)) error ("marcumq: B must be a non-negative value"); endif if (any (m < 1) || any (fix (m) != m)) error ("marcumq: M must be a positive integer"); endif [a, b, m] = tablify (a, b, m); q = arrayfun (@mq, a, b, m, tol); endfunction ## Subfunction to compute the actual Marcum Q function. function q = mq (a, b, m, tol) ## Special cases. if (b == 0) q = 1; N = 0; return; endif if (a == 0) k = 0:(m - 1); q = exp (-b^2 / 2) * sum (b.^(2 * k) ./ (2.^k .* factorial (k))); N = 0; return; endif ## The basic iteration. If a 1) for k = 1:m - 1 t = (d + 1 / d) * besseli (k, z, 1); S = S + t; d = d * x; endfor endif N = k++; else s = -1; c = 1; x = b / a; k = m; d = x^m; S = 0; N = 0; endif do t = d * besseli (abs (k), z, 1); S = S + t; d = d * x; N = k++; until (abs (t / S) < tol) q = c + s * exp (-(a - b)^2 / 2) * S; endfunction ## Internal helper function to create a table of like dimensions from arguments. function [varargout] = tablify (varargin) if (nargin < 2) varargout = varargin; return; endif empty = cellfun (@isempty, varargin); nrows = cellfun (@rows, varargin(! empty)); ridx = (nrows > 1); if (any (ridx)) rdim = nrows(ridx)(1); else rdim = 1; endif ncols = cellfun (@columns, varargin(! empty)); cidx = (ncols > 1); if (any (cidx)) cdim = ncols(cidx)(1); else cdim = 1; endif if (any (nrows(ridx) != rdim) || any (ncols(cidx) != cdim)) error ("tablify: incommensurate sizes"); endif varargout = varargin; varargout(! ridx) = cellindexmat (varargout(! ridx), ones (rdim, 1), ":"); varargout(! cidx) = cellindexmat (varargout(! cidx), ":", ones (1, cdim)); endfunction %% Tests for number and validity of arguments. %!error marcumq (1) %!error marcumq (-1, 1, 1, 1, 1) %!error marcumq (-1, 1) %!error marcumq (1, -1) %!error marcumq (1, 1, 0) %!error marcumq (1, 1, -1) %!error marcumq (1, 1, 1.1) ## Notes on tests and accuracy. ## ----------------------------------- ## The numbers used as the reference (Q) in the tables below are ## from J.I. Marcum, "Table of Q Functions", Rand Technical Report ## RM-339, 1950/1/1. ## ## There is one discrepancy in the tables. Marcum has ## Q(14.00,17.10) = 0.001078 ## while we compute ## Q(14.00,17.10) = 0.0010785053 = 0.001079 ## This is obviously a non-problem. ## ## As further tests, I created several different versions of the ## Q function computation, including a Bessel series expansion and ## numerical integration. All of them agree to with 10^(-16). %!test %! a = [0.00; 0.05; 1.00; 2.00; 3.00; 4.00; 5.00; 6.00; 7.00; 8.00; 9.00; 10.00; %! 11.00; 12.00; 13.00; 14.00; 15.00; 16.00; 17.00; 18.00; 19.00; 20.00; %! 21.00; 22.00; 23.00; 24.00]; %! b = [0.000000, 0.100000, 1.100000, 2.100000, 3.100000, 4.100000]; %! Q = [1.000000, 0.995012, 0.546074, 0.110251, 0.008189, 0.000224; %! 1.000000, 0.995019, 0.546487, 0.110554, 0.008238, 0.000226; %! 1.000000, 0.996971, 0.685377, 0.233113, 0.034727, 0.002092; %! 1.000000, 0.999322, 0.898073, 0.561704, 0.185328, 0.027068; %! 1.000000, 0.999944, 0.985457, 0.865241, 0.526735, 0.169515; %! 1.000000, 0.999998, 0.999136, 0.980933, 0.851679, 0.509876; %! 1.000000, 1.000000, 0.999979, 0.998864, 0.978683, 0.844038; %! 1.000000, 1.000000, 1.000000, 0.999973, 0.998715, 0.977300; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.999969, 0.998618; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999966; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000]; %! q = marcumq (a, b); %! assert (q, Q, 1e-6); %!test %! a = [0.00; 0.05; 1.00; 2.00; 3.00; 4.00; 5.00; 6.00; 7.00; 8.00; 9.00; 10.00; %! 11.00; 12.00; 13.00; 14.00; 15.00; 16.00; 17.00; 18.00; 19.00; 20.00; %! 21.00; 22.00; 23.00; 24.00]; %! b = [5.100000, 6.100000, 7.100000, 8.100000, 9.100000, 10.10000]; %! Q = [0.000002, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.000002, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.000049, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.001606, 0.000037, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.024285, 0.001420, 0.000032, 0.000000, 0.000000, 0.000000; %! 0.161412, 0.022812, 0.001319, 0.000030, 0.000000, 0.000000; %! 0.499869, 0.156458, 0.021893, 0.001256, 0.000028, 0.000000; %! 0.839108, 0.493229, 0.153110, 0.021264, 0.001212, 0.000027; %! 0.976358, 0.835657, 0.488497, 0.150693, 0.020806, 0.001180; %! 0.998549, 0.975673, 0.833104, 0.484953, 0.148867, 0.020458; %! 0.999965, 0.998498, 0.975152, 0.831138, 0.482198, 0.147437; %! 1.000000, 0.999963, 0.998458, 0.974742, 0.829576, 0.479995; %! 1.000000, 1.000000, 0.999962, 0.998426, 0.974411, 0.828307; %! 1.000000, 1.000000, 1.000000, 0.999961, 0.998400, 0.974138; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.999960, 0.998378; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999960; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000]; %! q = marcumq (a, b); %! assert (q, Q, 1e-6); %!test %! a = [0.00; 0.05; 1.00; 2.00; 3.00; 4.00; 5.00; 6.00; 7.00; 8.00; 9.00; 10.00; %! 11.00; 12.00; 13.00; 14.00; 15.00; 16.00; 17.00; 18.00; 19.00; 20.00; %! 21.00; 22.00; 23.00; 24.00]; %! b = [11.10000, 12.10000, 13.10000, 14.10000, 15.10000, 16.10000]; %! Q = [0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.000026, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.001155, 0.000026, 0.000000, 0.000000, 0.000000, 0.000000; %! 0.020183, 0.001136, 0.000025, 0.000000, 0.000000, 0.000000; %! 0.146287, 0.019961, 0.001120, 0.000025, 0.000000, 0.000000; %! 0.478193, 0.145342, 0.019778, 0.001107, 0.000024, 0.000000; %! 0.827253, 0.476692, 0.144551, 0.019625, 0.001096, 0.000024; %! 0.973909, 0.826366, 0.475422, 0.143881, 0.019494, 0.001087; %! 0.998359, 0.973714, 0.825607, 0.474333, 0.143304, 0.019381; %! 0.999959, 0.998343, 0.973546, 0.824952, 0.473389, 0.142803; %! 1.000000, 0.999959, 0.998330, 0.973400, 0.824380, 0.472564; %! 1.000000, 1.000000, 0.999958, 0.998318, 0.973271, 0.823876; %! 1.000000, 1.000000, 1.000000, 0.999958, 0.998307, 0.973158; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.999957, 0.998297; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999957; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000]; %! q = marcumq (a, b); %! assert (q, Q, 1e-6); %!test %! a = [0.00; 0.05; 1.00; 2.00; 3.00; 4.00; 5.00; 6.00; 7.00; 8.00; 9.00; 10.00; %! 11.00; 12.00; 13.00; 14.00; 15.00; 16.00; 17.00; 18.00; 19.00; 20.00; %! 21.00; 22.00; 23.00; 24.00]; %! b = [17.10000, 18.10000, 19.10000]; %! Q = [0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000000, 0.000000, 0.000000; %! 0.000024, 0.000000, 0.000000; %! 0.001078, 0.000024, 0.000000; %! 0.019283, 0.001071, 0.000023; %! 0.142364, 0.019197, 0.001065; %! 0.471835, 0.141976, 0.019121; %! 0.823429, 0.471188, 0.141630; %! 0.973056, 0.823030, 0.470608; %! 0.998289, 0.972965, 0.822671; %! 0.999957, 0.998281, 0.972883; %! 1.000000, 0.999957, 0.998274; %! 1.000000, 1.000000, 0.999956; %! 1.000000, 1.000000, 1.000000]; %! q = marcumq (a, b); %! assert (q, Q, 1e-6); ## The tests for M>1 were generating from Marcum's tables by ## using the formula ## Q_M(a,b) = Q(a,b) + exp(-(a-b)^2/2)*sum_{k=1}^{M-1}(b/a)^k*exp(-ab)*I_k(ab) %!test %! M = 2; %! a = [0.00; 0.05; 1.00; 2.00; 3.00; 4.00; 5.00; 6.00; 7.00; 8.00; 9.00; 10.00; %! 11.00; 12.00; 13.00; 14.00; 15.00; 16.00; 17.00; 18.00; 19.00; 20.00; %! 21.00; 22.00; 23.00; 24.00]; %! b = [ 0.00, 0.10, 2.10, 7.10, 12.10, 17.10]; %! Q = [1.000000, 0.999987, 0.353353, 0.000000, 0.000000, 0.000000; %! 1.000000, 0.999988, 0.353687, 0.000000, 0.000000, 0.000000; %! 1.000000, 0.999992, 0.478229, 0.000000, 0.000000, 0.000000; %! 1.000000, 0.999999, 0.745094, 0.000001, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.934771, 0.000077, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.992266, 0.002393, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.999607, 0.032264, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.999992, 0.192257, 0.000000, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.545174, 0.000000, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.864230, 0.000040, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.981589, 0.001555, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.998957, 0.024784, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.999976, 0.166055, 0.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.509823, 0.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.846066, 0.000032; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.978062, 0.001335; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.998699, 0.022409; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.999970, 0.156421; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.495223; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.837820; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.976328; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.998564; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999966; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000]; %! q = marcumq (a, b, M); %! assert (q, Q, 1e-6); %!test %! M = 5; %! a = [0.00; 0.05; 1.00; 2.00; 3.00; 4.00; 5.00; 6.00; 7.00; 8.00; 9.00; 10.00; %! 11.00; 12.00; 13.00; 14.00; 15.00; 16.00; 17.00; 18.00; 19.00; 20.00; %! 21.00; 22.00; 23.00; 24.00]; %! b = [ 0.00, 0.10, 2.10, 7.10, 12.10, 17.10]; %! Q = [1.000000, 1.000000, 0.926962, 0.000000, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.927021, 0.000000, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.947475, 0.000001, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.980857, 0.000033, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.996633, 0.000800, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.999729, 0.011720, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.999990, 0.088999, 0.000000, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.341096, 0.000000, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.705475, 0.000002, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.933009, 0.000134, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.993118, 0.003793, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.999702, 0.045408, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.999995, 0.238953, 0.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.607903, 0.000001; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.896007, 0.000073; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.987642, 0.002480; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.999389, 0.034450; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.999988, 0.203879; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.565165; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.876284; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.984209; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999165; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999983; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000]; %! q = marcumq (a, b, M); %! assert (q, Q, 1e-6); %!test %! M = 10; %! a = [0.00; 0.05; 1.00; 2.00; 3.00; 4.00; 5.00; 6.00; 7.00; 8.00; 9.00; 10.00; %! 11.00; 12.00; 13.00; 14.00; 15.00; 16.00; 17.00; 18.00; 19.00; 20.00; %! 21.00; 22.00; 23.00; 24.00]; %! b = [ 0.00, 0.10, 2.10, 7.10, 12.10, 17.10]; %! Q = [1.000000, 1.000000, 0.999898, 0.000193, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.999897, 0.000194, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.999931, 0.000416, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.999980, 0.002377, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.999997, 0.016409, 0.000000, 0.000000; %! 1.000000, 1.000000, 0.999999, 0.088005, 0.000000, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.302521, 0.000000, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.638401, 0.000000, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.894322, 0.000022, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.984732, 0.000840, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.998997, 0.014160, 0.000000; %! 1.000000, 1.000000, 1.000000, 0.999972, 0.107999, 0.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.391181, 0.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.754631, 0.000004; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.951354, 0.000266; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.995732, 0.006444; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.999843, 0.065902; %! 1.000000, 1.000000, 1.000000, 1.000000, 0.999998, 0.299616; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.676336; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.925312; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.992390; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999679; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 0.999995; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000; %! 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000]; %! q = marcumq (a, b, M); %! assert (q, Q, 1e-6); signal-1.4.5/inst/mexihat.m0000644000000000000000000000217414456505401013766 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{psi}, @var{x}] =} mexihat (@var{lb}, @var{ub}, @var{n}) ## Compute the Mexican hat wavelet. ## @end deftypefn function [psi,x] = mexihat(lb,ub,n) if (nargin < 3); print_usage; endif if (n <= 0) error("n must be strictly positive"); endif x = linspace(lb,ub,n); psi = (1-x.^2).*(2/(sqrt(3)*pi^0.25)) .* exp(-x.^2/2) ; endfunction signal-1.4.5/inst/meyeraux.m0000644000000000000000000000176514456505401014173 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} meyeraux (@var{x}) ## Compute the Meyer wavelet auxiliary function. ## @end deftypefn function y = meyeraux(x) if (nargin < 1); print_usage; endif y = 35.*x.^4-84.*x.^5+70.*x.^6-20.*x.^7; endfunction signal-1.4.5/inst/morlet.m0000644000000000000000000000213614456505401013627 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{psi}, @var{x}] =} morlet (@var{lb}, @var{ub}, @var{n}) ## Compute the Morlet wavelet. ## @end deftypefn function [psi,x] = morlet(lb,ub,n) if (nargin < 3); print_usage; endif if (n <= 0) error("n must be strictly positive"); endif x = linspace(lb,ub,n); psi = cos(5.*x) .* exp(-x.^2/2) ; endfunction signal-1.4.5/inst/movingrms.m0000644000000000000000000000554314456505401014353 0ustar0000000000000000## Copyright (C) 2012 Juan Pablo Carbajal ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{rmsx},@var{w}] =} movingrms (@var{x},@var{w},@var{rc},@var{Fs}=1) ## Calculate moving RMS value of the signal in @var{x}. ## ## The signal is convoluted against a sigmoid window of width @var{w} and ## risetime @var{rc}. The units of these parameters are relative to the value ## of the sampling frequency given in @var{Fs} (Default value = 1). ## ## Run @code{demo movingrms} to see an example. ## ## @seealso{sigmoid_train} ## @end deftypefn function [rmsx w]= movingrms (x,width, risetime, Fs=1) [N nc] = size (x); if width*Fs > N/2 idx = [1 N]; w = ones(N,1); else idx = round ((N + width*Fs*[-1 1])/2); w = sigmoid_train ((1:N)', idx, risetime*Fs); endif fw = fft (w.^2); fx = fft (x.^2); rmsx = real(ifft (fx.*fw)/(N-1)); rmsx (rmsx < eps*max(rmsx(:))) = 0; rmsx = circshift (sqrt (rmsx), round(mean(idx))); ##w = circshift (w, -idx(1)); endfunction %!demo %! N = 128; %! t = linspace(0,1,N)'; %! x = sigmoid_train (t,[0.4 inf],1e-2).*(2*rand(size(t))-1); %! Fs = 1/diff(t(1:2)); %! width = 0.05; %! rc = 5e-3; %! [wx w] = movingrms (zscore (x),width,rc,Fs); %! area (t,wx,'facecolor',[0.85 0.85 1],'edgecolor','b','linewidth',2); %! hold on; %! h = plot (t,x,'r-;Data;',t,w,'g-;Window;'); %! set (h, 'linewidth', 2); %! hold off; %! # --------------------------------------------------------------------------- %! # The shaded plot shows the local RMS of the Data: white noise with onset at %! # aprox. t== 0.4. %! # The observation window is also shown. %!demo %! N = 128; %! t = linspace(0,1,N)'; %! x = exp(-((t-0.5)/0.1).^2) + 0.1*rand(N,1); %! Fs = 1/diff(t(1:2)); %! width = 0.1; %! rc = 2e-3; %! [wx w] = movingrms (zscore (x),width,rc,Fs); %! area (t,wx,'facecolor',[0.85 0.85 1],'edgecolor','b','linewidth',2); %! hold on; %! h = plot (t,x,'r-;Data;',t,w,'g-;Window;'); %! set (h, 'linewidth', 2); %! hold off; %! # --------------------------------------------------------------------------- %! # The shaded plot shows the local RMS of the Data: Gausian with centered at %! # aprox. t== 0.5. %! # The observation window is also shown. signal-1.4.5/inst/mscohere.m0000644000000000000000000000455714456505401014143 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{Pxx}, @var{freq}] =} mscohere (@var{x}, @var{y}) ## @deftypefnx {Function File} {[@dots{}] =} mscohere (@var{x}, @var{y}, @var{window}) ## @deftypefnx {Function File} {[@dots{}] =} mscohere (@var{x}, @var{y}, @var{window}, @var{overlap}) ## @deftypefnx {Function File} {[@dots{}] =} mscohere (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}) ## @deftypefnx {Function File} {[@dots{}] =} mscohere (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}) ## @deftypefnx {Function File} {[@dots{}] =} mscohere (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}, @var{range}) ## @deftypefnx {Function File} {} mscohere (@dots{}) ## ## Estimate (mean square) coherence of signals @var{x} and @var{y}. ## Use the Welch (1967) periodogram/FFT method. ## @seealso{pwelch} ## @end deftypefn function varargout = mscohere(varargin) ## ## Check fixed argument if (nargin < 2 || nargin > 7) print_usage (); endif nvarargin = length(varargin); ## remove any pwelch RESULT args and add 'cross' for iarg=1:nvarargin arg = varargin{iarg}; if ( ~isempty(arg) && ischar(arg) && ( strcmp(arg,'power') || ... strcmp(arg,'cross') || strcmp(arg,'trans') || ... strcmp(arg,'coher') || strcmp(arg,'ypower') )) varargin{iarg} = []; endif endfor varargin{nvarargin+1} = 'coher'; ## if ( nargout==0 ) pwelch(varargin{:}); elseif ( nargout==1 ) Pxx = pwelch(varargin{:}); varargout{1} = Pxx; elseif ( nargout>=2 ) [Pxx,f] = pwelch(varargin{:}); varargout{1} = Pxx; varargout{2} = f; endif endfunction signal-1.4.5/inst/ncauer.m0000644000000000000000000000705414456505401013606 0ustar0000000000000000## Copyright (C) 2001 Paulo Neis ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} cauer(@var{Rp}, @var{Rs}, @var{n}) ## Analog prototype for Cauer filter. ## ## @table @asis ## @item Rp ## Passband ripple ## @item Rs ## Stopband ripple ## @item n ## Desired order ## @item z ## complex vector of zeros for the model. ## @item p ## complex vector of poles for the model. ## @item g ## gain value. ## @end table ## ## References: ## ## - Serra, Celso Penteado, Teoria e Projeto de Filtros, Campinas: CARTGRAF, ## 1983. ## ## - Lamar, Marcus Vinicius, Notas de aula da disciplina TE 456 - Circuitos ## Analogicos II, UFPR, 2001/2002. ## @end deftypefn function [zer, pol, T0] = ncauer (Rp, Rs, n) ## Cutoff frequency = 1: wp=1; ## Stop band edge ws: ws=__ellip_ws(n, Rp, Rs); k=wp/ws; k1=sqrt(1-k^2); q0=(1/2)*((1-sqrt(k1))/(1+sqrt(k1))); q= q0 + 2*q0^5 + 15*q0^9 + 150*q0^13; #(....) D=(10^(0.1*Rs)-1)/(10^(0.1*Rp)-1); ## Filter order maybe this, but not used now: ## n=ceil(log10(16*D)/log10(1/q)) l=(1/(2*n))*log((10^(0.05*Rp)+1)/(10^(0.05*Rp)-1)); sig01=0; sig02=0; for m=0 : 30 sig01=sig01+(-1)^m * q^(m*(m+1)) * sinh((2*m+1)*l); endfor for m=1 : 30 sig02=sig02+(-1)^m * q^(m^2) * cosh(2*m*l); endfor sig0=abs((2*q^(1/4)*sig01)/(1+2*sig02)); w=sqrt((1+k*sig0^2)*(1+sig0^2/k)); ## if rem(n,2) r=(n-1)/2; else r=n/2; endif ## wi=zeros(1,r); for ii=1 : r if rem(n,2) mu=ii; else mu=ii-1/2; endif soma1=0; for m=0 : 30 soma1 = soma1 + 2*q^(1/4) * ((-1)^m * q^(m*(m+1)) * sin(((2*m+1)*pi*mu)/n)); endfor soma2=0; for m=1 : 30 soma2 = soma2 + 2*((-1)^m * q^(m^2) * cos((2*m*pi*mu)/n)); endfor wi(ii)=(soma1/(1+soma2)); endfor ## Vi=sqrt((1-(k.*(wi.^2))).*(1-(wi.^2)/k)); A0i=1./(wi.^2); sqrA0i=1./(wi); B0i=((sig0.*Vi).^2 + (w.*wi).^2)./((1+sig0^2.*wi.^2).^2); B1i=(2 * sig0.*Vi)./(1 + sig0^2 * wi.^2); ## Gain T0: if rem(n,2) T0=sig0*prod(B0i./A0i)*sqrt(ws); else T0=10^(-0.05*Rp)*prod(B0i./A0i); endif ## zeros: zer=[i*sqrA0i, -i*sqrA0i]; ## poles: pol=[(-2*sig0*Vi+2*i*wi.*w)./(2*(1+sig0^2*wi.^2)), (-2*sig0*Vi-2*i*wi.*w)./(2*(1+sig0^2*wi.^2))]; ## If n odd, there is a real pole -sig0: if rem(n,2) pol=[pol, -sig0]; endif ## pol=(sqrt(ws)).*pol; zer=(sqrt(ws)).*zer; endfunction ## usage: ws = __ellip_ws(n, rp, rs) ## Calculate the stop band edge for the Cauer filter. function ws=__ellip_ws(n, rp, rs) kl0 = ((10^(0.1*rp)-1)/(10^(0.1*rs)-1)); k0 = (1-kl0); int = ellipke([kl0 ; k0]); ql0 = int(1); q0 = int(2); x = n*ql0/q0; kl = fminbnd(@(y) __ellip_ws_min(y,x) ,eps, 1-eps); ws = sqrt(1/kl); endfunction ## usage: err = __ellip_ws_min(kl, x) function err=__ellip_ws_min(kl, x) int=ellipke([kl; 1-kl]); ql=int(1); q=int(2); err=abs((ql/q)-x); endfunction signal-1.4.5/inst/nuttallwin.m0000644000000000000000000000507414456505401014532 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} nuttallwin (@var{m}) ## @deftypefnx {Function File} {} nuttallwin (@var{m}, "periodic") ## @deftypefnx {Function File} {} nuttallwin (@var{m}, "symmetric") ## Return the filter coefficients of a Blackman-Harris window defined by ## Nuttall of length @var{m}. ## ## If the optional argument @code{"periodic"} is given, the periodic form ## of the window is returned. This is equivalent to the window of length ## @var{m}+1 with the last coefficient removed. The optional argument ## @code{"symmetric"} is equivalent to not specifying a second argument. ## ## @seealso{blackman, blackmanharris} ## @end deftypefn function w = nuttallwin (m, opt) if (nargin < 1 || nargin > 2) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("nuttallwin: M must be a positive integer"); endif N = m - 1; if (nargin == 2) switch (opt) case "periodic" N = m; case "symmetric" N = m - 1; otherwise error ("nuttallwin: window type must be either \"periodic\" or \"symmetric\""); endswitch endif if (m == 1) w = 1; else a0 = 0.355768; a1 = 0.487396; a2 = 0.144232; a3 = 0.012604; n = [-N/2:(m-1)/2]'; w = a0 + a1.*cos(2.*pi.*n./N) + a2.*cos(4.*pi.*n./N) + a3.*cos(6.*pi.*n./N); endif endfunction %!assert (nuttallwin (1), 1) %!assert (nuttallwin (2), zeros (2, 1), eps) %!assert (nuttallwin (15), flipud (nuttallwin (15)), 10*eps); %!assert (nuttallwin (16), flipud (nuttallwin (16)), 10*eps); %!assert (nuttallwin (15), nuttallwin (15, "symmetric")); %!assert (nuttallwin (16)(1:15), nuttallwin (15, "periodic")); %% Test input validation %!error nuttallwin () %!error nuttallwin (0.5) %!error nuttallwin (-1) %!error nuttallwin (ones (1, 4)) %!error nuttallwin (1, 2) %!error nuttallwin (1, "invalid") signal-1.4.5/inst/parzenwin.m0000644000000000000000000000312514456505401014341 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} parzenwin (@var{m}) ## Return the filter coefficients of a Parzen window of length @var{m}. ## @seealso{rectwin, bartlett} ## @end deftypefn function w = parzenwin (m) if (nargin != 1) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("parzenwin: M must be a positive integer"); endif N = m - 1; n = -(N/2):N/2; n1 = n(find(abs(n) <= N/4)); n2 = n(find(n > N/4)); n3 = n(find(n < -N/4)); w1 = 1 -6.*(abs(n1)./(m/2)).^2 + 6*(abs(n1)./(m/2)).^3; w2 = 2.*(1-abs(n2)./(m/2)).^3; w3 = 2.*(1-abs(n3)./(m/2)).^3; w = [w3 w1 w2]'; endfunction %!assert (parzenwin (1), 1) %!assert (parzenwin (2), 0.25 * ones (2, 1)) %% Test input validation %!error parzenwin () %!error parzenwin (0.5) %!error parzenwin (-1) %!error parzenwin (ones (1, 4)) %!error parzenwin (1, 2) signal-1.4.5/inst/pburg.m0000644000000000000000000001407014456505401013444 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{psd},@var{f_out}] =} pburg(@var{x}, @var{poles}, @var{freq}, @var{Fs}, @var{range}, @var{method}, @var{plot_type}, @var{criterion}) ## Calculate Burg maximum-entropy power spectral density. ## ## The functions "arburg" and "ar_psd" do all the work. ## See "help arburg" and "help ar_psd" for further details. ## ## ARGUMENTS: ## ## All but the first two arguments are optional and may be empty. ## ## @table @asis ## @item x ## [vector] sampled data ## @item poles ## [integer scalar] required number of poles of the AR model ## @item freq ## [real vector] frequencies at which power spectral density is calculated. ## ## [integer scalar] number of uniformly distributed frequency ## values at which spectral density is calculated. ## [default=256] ## @item Fs ## [real scalar] sampling frequency (Hertz) [default=1] ## @end table ## ## CONTROL-STRING ARGUMENTS -- each of these arguments is a character string. ## ## Control-string arguments can be in any order after the other arguments. ## ## ## @table @asis ## @item range ## 'half', 'onesided' : frequency range of the spectrum is ## from zero up to but not including sample_f/2. Power ## from negative frequencies is added to the positive ## side of the spectrum. ## ## 'whole', 'twosided' : frequency range of the spectrum is ## -sample_f/2 to sample_f/2, with negative frequencies ## stored in "wrap around" order after the positive ## frequencies; e.g. frequencies for a 10-point 'twosided' ## spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 ## ## 'shift', 'centerdc' : same as 'whole' but with the first half ## of the spectrum swapped with second half to put the ## zero-frequency value in the middle. (See "help ## fftshift". If "freq" is vector, 'shift' is ignored. ## If model coefficients "ar_coeffs" are real, the default ## range is 'half', otherwise default range is 'whole'. ## ## @item method ## 'fft': use FFT to calculate power spectral density. ## ## 'poly': calculate spectral density as a polynomial of 1/z ## N.B. this argument is ignored if the "freq" argument is a ## vector. The default is 'poly' unless the "freq" ## argument is an integer power of 2. ## ## @item plot_type ## 'plot', 'semilogx', 'semilogy', 'loglog', 'squared' or 'db': ## specifies the type of plot. The default is 'plot', which ## means linear-linear axes. 'squared' is the same as 'plot'. ## 'dB' plots "10*log10(psd)". This argument is ignored and a ## spectrum is not plotted if the caller requires a returned ## value. ## ## @item criterion ## [optional string arg] model-selection criterion. Limits ## the number of poles so that spurious poles are not ## added when the whitened data has no more information ## in it (see Kay & Marple, 1981). Recognized values are ## ## 'AKICc' -- approximate corrected Kullback information ## criterion (recommended), ## ## 'KIC' -- Kullback information criterion ## ## 'AICc' -- corrected Akaike information criterion ## ## 'AIC' -- Akaike information criterion ## ## 'FPE' -- final prediction error" criterion ## ## The default is to NOT use a model-selection criterion ## @end table ## ## RETURNED VALUES: ## ## If return values are not required by the caller, the spectrum ## is plotted and nothing is returned. ## ## @table @asis ## @item psd ## [real vector] power-spectral density estimate ## @item f_out ## [real vector] frequency values ## @end table ## ## HINTS ## ## This function is a wrapper for arburg and ar_psd. ## ## See "help arburg", "help ar_psd". ## @end deftypefn function [psd,f_out]=pburg(x,poles,varargin) ## if ( nargin<2 ) error( 'pburg: need at least 2 args. Use "help pburg"' ); endif nvarargin=length(varargin); criterion=[]; ## ## Search for a "criterion" arg. If found, remove it ## from "varargin" list and feed it to arburg instead. for iarg = 1: nvarargin arrgh = varargin{iarg}; if ( ischar(arrgh) && ( strcmp(arrgh,'AKICc') ||... strcmp(arrgh,'KIC') || strcmp(arrgh,'AICc') ||... strcmp(arrgh,'AIC') || strcmp(arrgh,'FPE') ) ) criterion=arrgh; if ( nvarargin>1 ) varargin{iarg}= []; else varargin={}; endif endif endfor ## [ar_coeffs,residual]=arburg(x,poles,criterion); if ( nargout==0 ) ar_psd(ar_coeffs,residual,varargin{:}); elseif ( nargout==1 ) psd = ar_psd(ar_coeffs,residual,varargin{:}); elseif ( nargout>=2 ) [psd,f_out] = ar_psd(ar_coeffs,residual,varargin{:}); endif endfunction %!demo %! a = [1.0 -1.6216505 1.1102795 -0.4621741 0.2075552 -0.018756746]; %! Fs = 25; %! n = 16384; %! signal = detrend (filter (0.70181, a, rand (1, n))); %! % frequency shift by modulating with exp(j.omega.t) %! skewed = signal .* exp (2*pi*i*2/Fs*[1:n]); %! hold on; %! pburg (signal, 3, [], Fs); %! pburg (signal, 4, [], Fs, "whole"); %! pburg (signal, 5, 128, Fs, "shift", "semilogy"); %! pburg (skewed, 7, 128, Fs, "AKICc", "shift", "semilogy"); %! user_freq = [-0.2:0.02:0.2]*Fs; %! pburg (skewed, 7, user_freq, Fs, "AKICc", "semilogy"); %! hold off; signal-1.4.5/inst/peak2peak.m0000644000000000000000000000546414456505401014177 0ustar0000000000000000## Copyright (C) 2014 Georgios Ouzounis ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} peak2peak (@var{x}) ## @deftypefnx {Function File} {@var{y} =} peak2peak (@var{x}, @var{dim}) ## Compute the difference between the maximum and minimum values in the vector ## @var{x}. ## ## If @var{x} is a matrix, compute the difference for each column and return ## them in a row vector. ## ## If the optional argument @var{dim} is given, operate along this dimension. ## @seealso{max, min, peak2rms, rms, rssq} ## @end deftypefn function y = peak2peak (x, dim) if (nargin < 1 || nargin > 2) print_usage (); endif if (nargin > 1 && ! (isscalar (dim) && dim == fix (dim) && dim > 0)) error ("peak2peak: DIM must be an integer and a valid dimension"); endif if (nargin == 1) y = max (x) - min (x); else y = max (x, [], dim) - min (x, [], dim); endif endfunction %!test %! X = [23 42 85; 62 46 65; 18 40 28]; %! Y = peak2peak (X); %! assert (Y, [44 6 57]); %! Y = peak2peak (X, 1); %! assert (Y, [44 6 57]); %! Y = peak2peak (X, 2); %! assert (Y, [62; 19; 22]); %!test %! X = [71 62 33]; %! X(:, :, 2) = [88 36 21]; %! X(:, :, 3) = [83 46 85]; %! Y = peak2peak (X); %! T = [38]; %! T(:, :, 2) = [67]; %! T(:, :, 3) = [39]; %! assert (Y, T); %!test %! X = [71 72 22; 16 22 50; 29 44 14]; %! X(:, :, 2) = [10 15 62; 1 94 30; 72 43 53]; %! X(:, :, 3) = [57 98 32; 84 95 51; 25 24 0]; %! Y = peak2peak (X); %! T = [55 50 36]; %! T(:, :, 2) = [71 79 32]; %! T(:, :, 3) = [59 74 51]; %! assert (Y, T); %! Y = peak2peak (X, 2); %! T = [50; 34; 30]; %! T(:, :, 2) = [52; 93; 29]; %! T(:, :, 3) = [66; 44; 25]; %! assert (Y, T); %! Y = peak2peak (X, 3); %! T = [61 83 40; 83 73 21; 47 20 53]; %! assert (Y, T); %!test %! X = [60 61; 77 77]; %! X(:, :, 2) = [24 24; 22 74]; %! temp = [81 87; 88 62]; %! temp(:, :, 2) = [20 83; 81 18]; %! X(:, :, :, 2) = temp; %! Y = peak2peak (X); %! T = [17 16]; %! T(:, :, 2) = [2 50]; %! T2 = [7 25]; %! T2(:, :, 2) = [61 65]; %! T(:, :, :, 2) = T2; %! assert (Y, T); ## Test input validation %!error peak2peak () %!error peak2peak (1, 2, 3) %!error peak2peak (1, 1.5) %!error peak2peak (1, 0) signal-1.4.5/inst/peak2rms.m0000644000000000000000000000351014456505401014046 0ustar0000000000000000## Copyright (C) 2015 Andreas Weber ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} peak2rms (@var{x}) ## @deftypefnx {Function File} {@var{y} =} peak2rms (@var{x}, @var{dim}) ## Compute the ratio of the largest absolute value to the root-mean-square ## (RMS) value of the vector @var{x}. ## ## If @var{x} is a matrix, compute the peak-magnitude-to-RMS ratio for each ## column and return them in a row vector. ## ## If the optional argument @var{dim} is given, operate along this dimension. ## @seealso{max, min, peak2peak, rms, rssq} ## @end deftypefn function y = peak2rms (x, dim) if (nargin < 1 || nargin > 2) print_usage (); endif if (nargin == 1) y = max (abs (x)) ./ sqrt (meansq (x)); else y = max (abs (x), [], dim) ./ sqrt (meansq (x, dim)); endif endfunction %!assert (peak2rms (1), 1) %!assert (peak2rms (-5), 1) %!assert (peak2rms ([-2 3; 4 -2]), [4/sqrt(10), 3/sqrt((9+4)/2)]) %!assert (peak2rms ([-2 3; 4 -2], 2), [3/sqrt((9+4)/2); 4/sqrt(10)]) %!assert (peak2rms ([1 2 3], 3), [1 1 1]) ## Test input validation %!error peak2rms () %!error peak2rms (1, 2, 3) %!error peak2rms (1, 1.5) %!error peak2rms (1, -1) signal-1.4.5/inst/pei_tseng_notch.m0000644000000000000000000001043314456505401015474 0ustar0000000000000000## Copyright (C) 2011 Alexander Klein ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{b}, @var{a}] =} pei_tseng_notch (@var{frequencies}, @var{bandwidths}) ## Return coefficients for an IIR notch-filter with one or more filter frequencies and according (very narrow) bandwidths ## to be used with @code{filter} or @code{filtfilt}. ## The filter construction is based on an allpass which performs a reversal of phase at the filter frequencies. ## Thus, the mean of the phase-distorted and the original signal has the respective frequencies removed. ## See the demo for an illustration. ## ## Original source: ## Pei, Soo-Chang, and Chien-Cheng Tseng ## "IIR Multiple Notch Filter Design Based on Allpass Filter" ## 1996 IEEE Tencon ## doi: 10.1109/TENCON.1996.608814) ## @end deftypefn ## FIXME: Implement Laplace-space frequencies and bandwidths, and perhaps ## better range checking for bandwidths? function [ b, a ] = pei_tseng_notch ( frequencies, bandwidths ) err = nargchk ( 2, 2, nargin, "string" ); if ( err ) error ( err ); elseif ( !isvector ( frequencies ) || !isvector ( bandwidths ) ) error ( "All arguments must be vectors!" ) elseif ( length ( frequencies ) != length ( bandwidths ) ) error ( "All arguments must be of equal length!" ) elseif ( !all ( frequencies > 0 && frequencies < 1 ) ) error ( "All frequencies must be in (0, 1)!" ) elseif ( !all ( bandwidths > 0 && bandwidths < 1 ) ) error ( "All bandwidths must be in (0, 1)!" ) endif ## Ensure row vectors frequencies = frequencies (:)'; bandwidths = bandwidths (:)'; ## Normalize appropriately frequencies *= pi; bandwidths *= pi; M2 = 2 * length ( frequencies ); ## Splice center and offset frequencies ( Equation 11 ) omega = vec ( [ frequencies - bandwidths / 2; frequencies ] ); ## Splice center and offset phases ( Equations 12 ) factors = ( 1 : 2 : M2 ); phi = vec ( [ -pi * factors + pi / 2; -pi * factors ] ); ## Create linear equation t_beta = tan ( ( phi + M2 * omega ) / 2 ); Q = zeros ( M2 ); for k = 1 : M2 Q ( : ,k ) = sin ( k .* omega ) - t_beta .* cos ( k .* omega ); endfor ## Compute coefficients of system function ( Equations 19, 20 ) ... h_a = ( Q \ t_beta )' ; denom = [ 1, h_a ]; num = [ fliplr( h_a ), 1 ]; ## ... and transform them to coefficients for difference equations a = denom; b = ( num + denom ) / 2; endfunction %!test %! ## 2Hz bandwidth %! sf = 800; sf2 = sf/2; %! data=[sinetone(49,sf,10,1),sinetone(50,sf,10,1),sinetone(51,sf,10,1)]; %! [b, a] = pei_tseng_notch ( 50 / sf2, 2 / sf2 ); %! filtered = filter ( b, a, data ); %! damp_db = 20 * log10 ( max ( filtered ( end - 1000 : end, : ) ) ); %! assert ( damp_db, [ -3 -251.9 -3 ], -0.1 ) %!test %! ## 1Hz bandwidth %! sf = 800; sf2 = sf/2; %! data=[sinetone(49.5,sf,10,1),sinetone(50,sf,10,1),sinetone(50.5,sf,10,1)]; %! [b, a] = pei_tseng_notch ( 50 / sf2, 1 / sf2 ); %! filtered = filter ( b, a, data ); %! damp_db = 20 * log10 ( max ( filtered ( end - 1000 : end, : ) ) ); %! assert ( damp_db, [ -3 -240.4 -3 ], -0.1 ) %!demo %! sf = 800; sf2 = sf/2; %! data=[[1;zeros(sf-1,1)],sinetone(49,sf,1,1),sinetone(50,sf,1,1),sinetone(51,sf,1,1)]; %! [b,a]=pei_tseng_notch ( 50 / sf2, 2/sf2 ); %! filtered = filter(b,a,data); %! %! clf %! subplot ( columns ( filtered ), 1, 1) %! plot(filtered(:,1),";Impulse response;") %! subplot ( columns ( filtered ), 1, 2 ) %! plot(filtered(:,2),";49Hz response;") %! subplot ( columns ( filtered ), 1, 3 ) %! plot(filtered(:,3),";50Hz response;") %! subplot ( columns ( filtered ), 1, 4 ) %! plot(filtered(:,4),";51Hz response;") signal-1.4.5/inst/phasez.m0000644000000000000000000001246714456505401013627 0ustar0000000000000000## Copyright (C) 2023 Leonardo Araujo ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{phi}, @var{w}] = } phasez (@var{b}, @var{a}, @var{n}) ## @deftypefnx {Function File} {[@var{phi}, @var{w}] = } phasez (@var{b}, @var{a}) ## @deftypefnx {Function File} {[@var{phi}, @var{w}] = } phasez (@var{sos}, @var{n}) ## @deftypefnx {Function File} {[@var{phi}, @var{w}] = } phasez (@var{sos}) ## @deftypefnx {Function File} {[@var{phi}, @var{w}] = } phasez (@dots{}, @var{n}, "whole") ## @deftypefnx {Function File} {[@var{phi}, @var{w}] = } phasez (@dots{}, @var{n}, Fs) ## @deftypefnx {Function File} {} phasez (@dots{}) ## ## Compute the phase response of digital filter defined either by its ## coefficients (@var{b} and @var{a} are the numerator and denominator ## coefficients respectively) or by its second-order sections representation, ## given by the matrix @var{sos}. The output @var{phi} is the phase response ## computed in a vector the vector of frequencies @var{w}. ## ## The phase response is evaluated at @var{n} angular frequencies between ## 0 and ## @ifnottex ## pi. ## @end ifnottex ## @tex ## $\pi$. ## @end tex ## ## @noindent ## If @var{a} is omitted, the denominator is assumed to be 1 (this ## corresponds to a simple FIR filter). ## ## If @var{n} is omitted, a value of 512 is assumed. ## ## If the third/forth argument, @qcode{"whole"}, is given, the response is ## evaluated at @var{n} angular frequencies between 0 and ## @ifnottex ## 2*pi. ## @end ifnottex ## @tex ## $\pi$. ## @end tex ## It is possible also to pass the value @qcode{"half"}, which will lead to ## the default behaviour. ## ## Example: ## @example ## [b, a] = butter (2, [.15,.3]); ## phasez (b, a); ## @end example ## ## Ref [1] Oppenheim, Alan, and Ronald Schafer. Discrete-Time Signal Processing. ## 3rd edition, Pearson, 2009. ## ## @seealso{freqz, phasedelay} ## @end deftypefn function [phi, w] = phasez (b, a, n, region, Fs) if (nargin < 1 || nargin > 5) print_usage; elseif nargin == 1 a = 1; region = Fs = []; n = 512; elseif nargin == 2 if (! ismatrix (b) || ! ismatrix (a)), print_usage; endif n = 512; region = Fs = []; elseif nargin == 3 if size (b, 1) > 1 && size (b, 2) == 6, if ischar (n) region = n; n = a; Fs = []; else Fs = n; n = a; endif else if ! isscalar (n), print_usage; endif region = Fs = []; endif elseif nargin ==4 if ischar (region) Fs = []; else Fs = region; region = []; endif elseif nargin == 5 && ! ischar (region), print_usage; endif if isrow (b) [h, w] = freqz (b, a, n, region, Fs); phi = my_unwrap(angle(h)); elseif (size (b, 1) > 1 && size (b, 2) == 6) phi = zeros (n, 1); for i=1:size (b,1) [h, w] = freqz (b(i,1:3), b(i,4:6), n, region, Fs); phi += my_unwrap(angle(h)); endfor endif switch nargout case 0 if isempty (Fs), plot (w/pi, phi); xlabel ( 'Normalized Frequency (\times\pi rad/sample)' ); else plot (w, phi); xlabel ( "Frequency (Hz)" ); xlim ([0 Fs/2]); endif ylabel ( "Phase (radians)" ); grid ("on"); case 1 varargout = {phi}; case 2 varargout = {phi, w}; endswitch endfunction %!demo %! N = 2; %! b = ones (1, N)/N; %! a = 1; %! [phi, w] = phasez (b, a) %! ## test input validation %!error n = phasez () %!error n = phasez (1, 1, 1, 1, 1) %!error n = phasez (1:10, 1:10, 1:10) %!error n = phasez (ones (3), ones (3)) %!test %! % moving average %! N = 2; %! b = ones (1, N)/N; %! a = 1; %! [phi, w] = phasez (b, a); %! PHI = -w * (N-1) /2; %! assert (phi, PHI, eps^(3/5)) %!test %! % moving average %! N = 5; %! b = ones (1, N)/N; %! a = 1; %! [phi, w] = phasez (b, a); %! PHI = -w * (N-1) /2; %! assert (phi, PHI, eps^(3/5)) %!test %! % Oppenheim - Example 5.6 - 2nd-Order IIR System %! % %! % 1 %! % H(z) = --------------------------- %! % 1 − 2r cos θz^−1 + r^2 z^−2 %! % %! % ang(H(e^jω)) = − arctan[ r sin(ω − θ) / (1 − r cos(ω − θ)) ] − arctan[ r sin(ω + θ) / (1 − r cos(ω + θ)) ] %! % %! r = 0.5; theta = pi/4; %! b = 1; %! a = [ 1 -2*r*cos(theta) r^2]; %! [phi, w] = phasez (b, a); %! PHI = - atan ( r*sin (w - theta) ./ (1 - r*cos (w - theta)) ) - atan ( r*sin (w + theta) ./ (1 - r*cos (w+theta)) ); %! assert (phi, PHI, eps^(3/5)) function x = my_unwrap ( x ) stillunwrap = true; while stillunwrap, dx = diff (x); idx = find (abs(dx) > pi-0.05 , 1); if ! isempty (idx), if dx(idx) > 0, x(idx+1:end)-=pi; else x(idx+1:end)+=pi; endif else stillunwrap = false; endif endwhile endfunction signal-1.4.5/inst/polystab.m0000644000000000000000000000204314456505401014157 0ustar0000000000000000## Copyright (C) 2001 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## b = polystab(a) ## ## Stabilize the polynomial transfer function by replacing all roots ## outside the unit circle with their reflection inside the unit circle. function b = polystab(a) r = roots(a); v = find(abs(r)>1); r(v) = 1./conj(r(v)); b = a(1) * poly ( r ); if isreal(a), b = real(b); endif endfunction signal-1.4.5/inst/pow2db.m0000644000000000000000000000341514456505401013523 0ustar0000000000000000## Copyright (C) 2018 P Sudeepam ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} pow2db (@var{x}) ## Convert power to decibels (dB). ## ## The decibel value of @var{x} is defined as ## @tex ## $d = 10 * \log_{10} (x)$. ## @end tex ## @ifnottex ## @var{d} = @code{10 * log10 (x)}. ## @end ifnottex ## ## If @var{x} is a vector, matrix, or N-dimensional array, the decibel value ## is computed over the elements of @var{x}. ## ## Examples: ## ## @example ## @group ## pow2db ([0, 10, 100]) ## @result{} -Inf 10 20 ## @end group ## @end example ## @seealso{db2pow} ## @end deftypefn function y = pow2db (x) if (nargin != 1) print_usage (); endif if (any (x < 0)) error ("pow2db: X must be non-negative"); endif y = 10 .* log10 (x); endfunction %!shared pow %! pow = [0, 10, 20, 60, 100]; %!assert (pow2db (pow), [-Inf, 10.000, 13.010, 17.782, 20.000], 0.01) %!assert (pow2db (pow'), [-Inf; 10.000; 13.010; 17.782; 20.000], 0.01) ## Test input validation %!error pow2db () %!error pow2db (1, 2) %!error pow2db (-5) %!error pow2db ([-5 7]) signal-1.4.5/inst/primitive.m0000644000000000000000000000470314456505401014337 0ustar0000000000000000## Copyright (C) 2013 Juan Pablo Carbajal ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{F} =} primitive (@var{f}, @var{t}, @var{F0}) ## Calculate the primitive of a function. ## ## The function approximates the primitive (indefinite integral) of the ## univariate function handle @var{f} with constant of integration @var{F0}. ## The output is the primitive evaluated at the points @var{t}. The vector ## @var{t} must be ordered and ascending. ## ## This function is a fancy way of calculating the cumulative sum, ## ## @command{F = cumsum (f(t).*diff (t)([1 1:end]))}. ## ## Example: ## @example ## @group ## f = @@(t) sin (2 * pi * 3 * t); ## t = [0; sort(rand (100, 1))]; ## F = primitive (f, t, 0); ## t_true = linspace (0, 1, 1e3).'; ## F_true = (1 - cos (2 * pi * 3 * t_true)) / (2 * pi * 3); ## plot (t, F, 'o', t_true, F_true); ## @end group ## @end example ## ## @seealso{quadgk, cumsum} ## @end deftypefn function F = primitive (f, t, C = 0) if (nargin < 2 || nargin > 3) print_usage (); endif i_chunk (0, 0, []); F = arrayfun (@(x) i_chunk (f, x, C), t); endfunction function F = i_chunk (f, t, init) persistent F_prev t0 if isempty (init) F_prev = []; t0 = 0; elseif isempty (F_prev) F_prev = init; else F_prev += quadgk (f, t0, t); t0 = t; endif F = F_prev; endfunction %!demo %! f = @(t) sin (2*pi*3*t); %! t = [0; sort(rand (100, 1))]; %! F = primitive (f, t, 0); %! t_true = linspace (0, 1, 1e3).'; %! F_true = (1 - cos (2 * pi * 3 * t_true)) / (2 * pi * 3); %! h = plot (t, F, "o;Numerical primitive;", t_true, F_true, "-;True primitive;"); %! set (h, "linewidth", 2); %! title ("Numerical primitive evaluated at random time points"); ## Test input validation %!error primitive () %!error primitive (1) %!error primitive (1, 2, 3, 4) signal-1.4.5/inst/private/0000755000000000000000000000000014456505401013617 5ustar0000000000000000signal-1.4.5/inst/private/__fwht_opts__.m0000644000000000000000000000450614456505401016613 0ustar0000000000000000## Copyright (C) 2013-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{y}, @var{len}] =} __fwht_opts__ (@var{caller}, @var{x}, @var{n}, @var{order}) ## Undocumented internal function. ## @end deftypefn function [y, len] = __fwht_opts__ (caller, x, n, order) if (nargin < 1) print_usage (); elseif (nargin != 4) print_usage (caller); endif [nr, nc] = size (x); if (isempty (n)) if (nr == 1) n = 2^nextpow2 (nc); else n = 2^nextpow2 (nr); endif elseif (!(isscalar (n) && n == fix (n) && n > 0)) error ("%s: N must be a positive scalar", caller); else f = log2(n); if (f != fix (f)) error ("%s: N must be a power of 2", caller); endif endif if (isempty (order)) order = "sequency"; endif if (!(strncmp (order, "dyadic", 6) || strncmp (order, "hadamard", 8) || strncmp (order, "sequency", 8))) error ("%s: invalid order option", caller); endif if (nr == 1) nc = n; x = x(:); else nr = n; endif ## Zero-based index for normal Hadamard ordering idx = 0:n-1; ## Gray code permutation of index for alternate orderings idx_bin = dec2bin (idx) - "0"; idx_bin_a = idx_bin(:,1:end-1); idx_bin_b = idx_bin(:,2:end); idx_bin(:,2:end) = mod (idx_bin_a + idx_bin_b, 2); idx_bin = char (idx_bin + "0"); if (strncmp (order, "dyadic", 6)) idx = bin2dec (fliplr (dec2bin (idx))) + 1; elseif (strncmp (order, "sequency", 8)) idx = bin2dec (fliplr (idx_bin)) + 1; else idx += 1; endif len = n; x = postpad (x, len); if (len < 2) y = x; else y = __fwht__ (x); endif y = reshape (y(idx,:), nr, nc); endfunction signal-1.4.5/inst/private/h1_z_deriv.m0000644000000000000000000000462014456505401016031 0ustar0000000000000000## Copyright (C) 2007 R.G.H. Eschauzier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{b} =} h1_z_deriv (@var{n}, @var{p}, @var{ts}) ## Undocumented internal function. This function is used by the impinvar ## and invimpinvar functions in the signal package. ## @end deftypefn ## Adapted by CarnĂ« Draug on 2011 ## Find {-zd/dz}^n*H1(z). I.e., first differentiate, then multiply by -z, then differentiate, etc. ## The result is (ts^(n+1))*(b(1)*p/(z-p)^1 + b(2)*p^2/(z-p)^2 + b(n+1)*p^(n+1)/(z-p)^(n+1)). ## Works for n>0. function b = h1_z_deriv(n, p, ts) ## Build the vector d that holds coefficients for all the derivatives of H1(z) ## The results reads d(n)*z^(1)*(d/dz)^(1)*H1(z) + d(n-1)*z^(2)*(d/dz)^(2)*H1(z) +...+ d(1)*z^(n)*(d/dz)^(n)*H1(z) d = (-1)^n; # Vector with the derivatives of H1(z) for i= (1:n-1) d = [d 0]; # Shift result right (multiply by -z) d += prepad(polyder(d), i+1, 0, 2); # Add the derivative endfor ## Build output vector b = zeros (1, n + 1); for i = (1:n) b += d(i) * prepad(h1_deriv(n-i+1), n+1, 0, 2); endfor b *= ts^(n+1)/factorial(n); ## Multiply coefficients with p^i, where i is the index of the coeff. b.*=p.^(n+1:-1:1); endfunction ## Find (z^n)*(d/dz)^n*H1(z), where H1(z)=ts*z/(z-p), ts=sampling period, ## p=exp(sm*ts) and sm is the s-domain pole with multiplicity n+1. ## The result is (ts^(n+1))*(b(1)*p/(z-p)^1 + b(2)*p^2/(z-p)^2 + b(n+1)*p^(n+1)/(z-p)^(n+1)), ## where b(i) is the binomial coefficient bincoeff(n,i) times n!. Works for n>0. function b = h1_deriv(n) b = factorial(n)*bincoeff(n,0:n); # Binomial coefficients: [1], [1 1], [1 2 1], [1 3 3 1], etc. b *= (-1)^n; endfunction signal-1.4.5/inst/private/inv_residue.m0000644000000000000000000000446514456505401016322 0ustar0000000000000000## Copyright (C) 2007 R.G.H. Eschauzier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{b_out}, @var{a_out}] =} inv_residue (@var{r_in}, @var{p_in}, @var{k_in}, @var{tol}) ## Undocumented internal function. This function is used by the impinvar ## and invimpinvar functions in the signal package. ## @end deftypefn ## Adapted by CarnĂ« Draug on 2011 ## Inverse of Octave residue function function [b_out, a_out] = inv_residue(r_in, p_in, k_in, tol) n = length(r_in); # Number of poles/residues k = 0; # Capture constant term if (length(k_in)==1) # A single direct term (order N = order D) k = k_in(1); # Capture constant term elseif (length(k_in)>1) # Greater than one means non-physical system error("Order numerator > order denominator"); endif a_out = poly(p_in); b_out = zeros(1,n+1); b_out += k*a_out; # Constant term: add k times denominator to numerator i=1; while (i<=n) term = [1 -p_in(i)]; # Term to be factored out p = r_in(i)*deconv(a_out,term); # Residue times resulting polynomial p = prepad(p, n+1, 0, 2); # Pad for proper length b_out += p; m = 1; mterm = term; first_pole = p_in(i); while (i ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{p_out} =} polyrev (@var{p_in}) ## Undocumented internal function. This function is used by the impinvar ## and invimpinvar functions in the signal package. ## @end deftypefn ## Adapted by CarnĂ« Draug on 2011 ## Reverse the coefficients of a polynomial function p_out = polyrev (p_in) p_out = p_in(end:-1:1); endfunction signal-1.4.5/inst/private/to_real.m0000644000000000000000000000221614456505401015423 0ustar0000000000000000## Copyright (C) 2007 R.G.H. Eschauzier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{p_out} =} to_real (@var{p_in}) ## Undocumented internal function. This function is used by the impinvar ## and invimpinvar functions in the signal package. ## @end deftypefn ## Adapted by CarnĂ« Draug on 2011 ## Round complex number to nearest real number function p_out = to_real(p_in) p_out = abs(p_in) .* sign(real(p_in)); endfunction signal-1.4.5/inst/private/validate_filter_bands.m0000644000000000000000000000524214456505401020305 0ustar0000000000000000## Copyright (C) 2014-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} validate_filter_bands (@var{func}, @var{wp}, @var{ws}) ## @deftypefnx {Function File} {} validate_filter_bands (@var{func}, @var{wp}, @var{ws}, "s") ## Validate filter design frequency response bands. This is an internal ## convenience function used by @code{buttord}, @code{cheb1ord}, ## @code{cheb2ord}, @code{ellipord}. ## @end deftypefn function validate_filter_bands (func, wp, ws, opt) if (nargin < 3 || nargin > 4) print_usage (); elseif (nargin == 4 && ! strcmp (opt, "s")) error ("validate_filter_bands: OPT must be the string \"s\""); elseif (! ischar (func)) error ("validate_filter_bands: FUNC must be a string"); endif if (nargin == 4 && strcmp (opt, "s")) s_domain = true; else s_domain = false; endif if (! (isvector (wp) && isvector (ws) && (numel (wp) == numel (ws)))) error ([func ": WP and WS must both be scalars or vectors of length 2\n"]); elseif (! ((numel (wp) == 1) || (numel (wp) == 2))) error ([func ": WP and WS must both be scalars or vectors of length 2\n"]); elseif (! s_domain && ! (isreal (wp) && all (wp >= 0) && all (wp <= 1))) error ([func ": all elements of WP must be in the range [0,1]\n"]); elseif (! s_domain && ! (isreal (ws) && all (ws >= 0) && all (ws <= 1))) error ([func ": all elements of WS must be in the range [0,1]\n"]); elseif (s_domain && ! (isreal (wp) && all (wp >= 0))) error ([func ": all elements of WP must be non-negative\n"]); elseif (s_domain && ! (isreal (ws) && all (ws >= 0))) error ([func ": all elements of WS must be non-negative\n"]); elseif ((numel (wp) == 2) && (wp(2) <= wp(1))) error ([func ": WP(1) must be less than WP(2)\n"]) elseif ((numel (ws) == 2) && (ws(2) <= ws(1))) error ([func ": WS(1) must be less than WS(2)\n"]) elseif ((numel (wp) == 2) && (all (wp > ws) || all (ws > wp))) error ([func ": WP must be contained by WS or WS must be contained by WP\n"]); endif endfunction signal-1.4.5/inst/pulstran.m0000644000000000000000000001407414456505401014201 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} pulstran (@var{t}, @var{d}, @var{func}, @dots{}) ## @deftypefnx {Function File} {@var{y} =} pulstran (@var{t}, @var{d}, @var{p}) ## @deftypefnx {Function File} {@var{y} =} pulstran (@var{t}, @var{d}, @var{p}, @var{Fs}) ## @deftypefnx {Function File} {@var{y} =} pulstran (@var{t}, @var{d}, @var{p}, @var{Fs}, @var{method}) ## ## Generate the signal y=sum(func(t+d,...)) for each d. If d is a ## matrix of two columns, the first column is the delay d and the second ## column is the amplitude a, and y=sum(a*func(t+d)) for each d,a. ## Clearly, func must be a function which accepts a vector of times. ## Any extra arguments needed for the function must be tagged on the end. ## ## Example: ## @example ## fs = 11025; # arbitrary sample rate ## f0 = 100; # pulse train sample rate ## w = 0.001; # pulse width of 1 millisecond ## auplot (pulstran (0:1/fs:0.1, 0:1/f0:0.1, "rectpuls", w), fs); ## @end example ## ## If instead of a function name you supply a pulse shape sampled at ## frequency Fs (default 1 Hz), an interpolated version of the pulse ## is added at each delay d. The interpolation stays within the the ## time range of the delayed pulse. The interpolation method defaults ## to linear, but it can be any interpolation method accepted by the ## function interp1. ## ## Example: ## @example ## fs = 11025; # arbitrary sample rate ## f0 = 100; # pulse train sample rate ## w = boxcar(10); # pulse width of 1 millisecond at 10 kHz ## auplot (pulstran (0:1/fs:0.1, 0:1/f0:0.1, w, 10000), fs); ## @end example ## @end deftypefn ## FIXME: Make it faster. It is currently unusable for anything real. ## It may not be possible to speed it up with the present interface. ## See speech/voice.m for a better way. ## Note that pulstran can be used for some pretty strange things such ## as simple band-limited interpolation: ## xf = 0:0.05:10; yf = sin(2*pi*xf/5); ## xp = 0:10; yp = sin(2*pi*xp/5); # .2 Hz sine sampled every second ## s = pulstran(xf, [xp, yp],'sinc'); ## plot(f, yf, ";original;", xf, s, ";sinc;",xp,yp,"*;;"); ## You wouldn't want to do this in practice since it is expensive, and ## since it works much better with a windowed sinc function, at least ## for short samples. function y = pulstran(t, d, pulse, varargin) if nargin<3 || (!ischar(pulse) && nargin>5) print_usage; endif y = zeros(size(t)); if isempty(y), return; endif if rows(d) == 1, d=d'; endif if columns(d) == 2, a=d(:,2); else a=ones(rows(d),1); endif if ischar(pulse) ## apply function t+d for all d for i=1:rows(d) y = y+a(i)*feval(pulse,t-d(i,1),varargin{:}); endfor else ## interpolate each pulse at the specified times Fs = 1; method = 'linear'; if nargin==4 arg=varargin{1}; if ischar(arg), method=arg; else Fs = arg; endif elseif nargin==5 Fs = varargin{1}; method = varargin{2}; endif span = (length(pulse)-1)/Fs; t_pulse = (0:length(pulse)-1)/Fs; for i=1:rows(d) dt = t-d(i,1); idx = find(dt>=0 & dt<=span); y(idx) = y(idx) + a(i)*interp1(t_pulse, pulse, dt(idx), method); endfor endif endfunction %!error pulstran %!error pulstran(1,2,3,4,5,6) %!## parameter size and shape checking %!shared t,d %! t = 0:0.01:1; d=0:0.1:1; %!assert (isempty(pulstran([], d, 'sin'))); %!assert (pulstran(t, [], 'sin'), zeros(size(t))); %!assert (isempty(pulstran([], d, boxcar(5)))); %!assert (pulstran(t, [], boxcar(5)), zeros(size(t))); %!assert (size(pulstran(t,d,'sin')), size(t)); %!assert (size(pulstran(t,d','sin')), size(t)); %!assert (size(pulstran(t',d,'sin')), size(t')); %!assert (size(pulstran(t,d','sin')), size(t)); %!demo %! fs = 11025; # arbitrary sample rate %! f0 = 100; # pulse train sample rate %! w = 0.003; # pulse width of 3 milliseconds %! t = 0:1/fs:0.1; d=0:1/f0:0.1; # define sample times and pulse times %! a = hanning(length(d)); # define pulse amplitudes %! %! subplot(221); %! x = pulstran(t', d', 'rectpuls', w); %! plot([0:length(x)-1]*1000/fs, x); %! hold on; plot(d*1000,ones(size(d)),'g*;pulse;'); hold off; %! ylabel("amplitude"); xlabel("time (ms)"); %! title("rectpuls"); %! %! subplot(223); %! x = pulstran(f0*t, [f0*d', a], 'sinc'); %! plot([0:length(x)-1]*1000/fs, x); %! hold on; plot(d*1000,a,'g*;pulse;'); hold off; %! ylabel("amplitude"); xlabel("time (ms)"); %! title("sinc => band limited interpolation"); %! %! subplot(222); %! pulse = boxcar(30); # pulse width of 3 ms at 10 kHz %! x = pulstran(t, d', pulse, 10000); %! plot([0:length(x)-1]*1000/fs, x); %! hold on; plot(d*1000,ones(size(d)),'g*;pulse;'); hold off; %! ylabel("amplitude"); xlabel("time (ms)"); %! title("interpolated boxcar"); %! %! subplot(224); %! pulse = sin(2*pi*[0:0.0001:w]/w).*[w:-0.0001:0]; %! x = pulstran(t', [d', a], pulse', 10000); %! plot([0:length(x)-1]*1000/fs, x); %! hold on; plot(d*1000,a*w,'g*;pulse;'); hold off; title(""); %! ylabel("amplitude"); xlabel("time (ms)"); %! title("interpolated asymmetric sin"); %! %! %---------------------------------------------------------- %! % Should see (1) rectangular pulses centered on *, %! % (2) rectangular pulses to the right of *, %! % (3) smooth interpolation between the *'s, and %! % (4) asymmetric sines to the right of * signal-1.4.5/inst/pwelch.m0000644000000000000000000011431014456505401013605 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{spectra},@var{freq}] =} pwelch(@var{x}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}, @var{range}, @var{plot_type}, @var{detrend}, @var{sloppy}) ## Estimate power spectral density of data "x" by the Welch (1967) periodogram/FFT method. ## ## All arguments except "x" are optional. ## ## The data is divided into segments. If "window" is a vector, each ## segment has the same length as "window" and is multiplied by "window" ## before (optional) zero-padding and calculation of its periodogram. If ## "window" is a scalar, each segment has a length of "window" and a ## Hamming window is used. ## ## The spectral density is the mean of the periodograms, scaled so that ## area under the spectrum is the same as the mean square of the ## data. This equivalence is supposed to be exact, but in practice there ## is a mismatch of up to 0.5% when comparing area under a periodogram ## with the mean square of the data. ## ## [spectra,freq] = pwelch(x,y,window,overlap,Nfft,Fs, ## range,plot_type,detrend,sloppy,results) ## ## Two-channel spectrum analyser. Estimate power spectral density, cross- ## spectral density, transfer function and/or coherence functions of time- ## series input data "x" and output data "y" by the Welch (1967) ## periodogram/FFT method. ## ## pwelch treats the second argument as "y" if there is a control-string ## argument "cross", "trans", "coher" or "ypower"; "power" does not force ## the 2nd argument to be treated as "y". All other arguments are ## optional. All spectra are returned in matrix "spectra". ## ## [spectra,Pxx_ci,freq] = pwelch(x,window,overlap,Nfft,Fs,conf, ## range,plot_type,detrend,sloppy) ## ## [spectra,Pxx_ci,freq] = pwelch(x,y,window,overlap,Nfft,Fs,conf, ## range,plot_type,detrend,sloppy,results) ## ## Estimates confidence intervals for the spectral density. ## ## See Hint (7) below for compatibility options. ## ## Confidence level "conf" is the 6th or 7th numeric argument. If "results" control-string ## arguments are used, one of them must be "power" when the "conf" ## argument is present; pwelch can estimate confidence intervals only for ## the power spectrum of the "x" data. It does not know how to estimate ## confidence intervals of the cross-power spectrum, transfer function or ## coherence; if you can suggest a good method, please send a bug report. ## ## ARGUMENTS ## ## All but the first argument are optional and may be empty, except that ## the "results" argument may require the second argument to be "y". ## @table @asis ## @item x ## [non-empty vector] system-input time-series data ## @item y ## [non-empty vector] system-output time-series data ## @item window ## [real vector] of window-function values between 0 and 1; the ## data segment has the same length as the window. ## Default window shape is Hamming. ## ## [integer scalar] length of each data segment. The default ## value is window=sqrt(length(x)) rounded up to the ## nearest integer power of 2; see 'sloppy' argument. ## ## @item overlap ## [real scalar] segment overlap expressed as a multiple of ## window or segment length. 0 <= overlap < 1, ## The default is overlap=0.5 . ## ## @item Nfft ## [integer scalar] Length of FFT. The default is the length ## of the "window" vector or has the same value as the ## scalar "window" argument. If Nfft is larger than the ## segment length, "seg_len", the data segment is padded ## with "Nfft-seg_len" zeros. The default is no padding. ## Nfft values smaller than the length of the data ## segment (or window) are ignored silently. ## ## @item Fs ## [real scalar] sampling frequency (Hertz); default=1.0 ## ## @item conf ## [real scalar] confidence level between 0 and 1. Confidence ## intervals of the spectral density are estimated from ## scatter in the periodograms and are returned as Pxx_ci. ## Pxx_ci(:,1) is the lower bound of the confidence ## interval and Pxx_ci(:,2) is the upper bound. If there ## are three return values, or conf is an empty matrix, ## confidence intervals are calculated for conf=0.95 . ## If conf is zero or is not given, confidence intervals ## are not calculated. Confidence intervals can be ## obtained only for the power spectral density of x; ## nothing else. ## @end table ## ## CONTROL-STRING ARGUMENTS -- each of these arguments is a character string. ## Control-string arguments must be after the other arguments but can be in ## any order. ## ## @table @asis ## @item range ## 'half', 'onesided' : frequency range of the spectrum is ## zero up to but not including Fs/2. Power from ## negative frequencies is added to the positive side of ## the spectrum, but not at zero or Nyquist (Fs/2) ## frequencies. This keeps power equal in time and ## spectral domains. See reference [2]. ## ## 'whole', 'twosided' : frequency range of the spectrum is ## -Fs/2 to Fs/2, with negative frequencies ## stored in "wrap around" order after the positive ## frequencies; e.g. frequencies for a 10-point 'twosided' ## spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 ## ## 'shift', 'centerdc' : same as 'whole' but with the first half ## of the spectrum swapped with second half to put the ## zero-frequency value in the middle. (See "help ## fftshift". ## ## If data (x and y) are real, the default range is 'half', ## otherwise default range is 'whole'. ## ## @item plot_type ## 'plot', 'semilogx', 'semilogy', 'loglog', 'squared' or 'db': ## specifies the type of plot. The default is 'plot', which ## means linear-linear axes. 'squared' is the same as 'plot'. ## 'dB' plots "10*log10(psd)". This argument is ignored and a ## spectrum is not plotted if the caller requires a returned ## value. ## ## @item detrend ## 'no-strip', 'none' -- do NOT remove mean value from the data ## ## 'short', 'mean' -- remove the mean value of each segment from ## each segment of the data. ## ## 'linear', -- remove linear trend from each segment of ## the data. ## ## 'long-mean' -- remove the mean value from the data before ## splitting it into segments. This is the default. ## ## @item sloppy ## 'sloppy': FFT length is rounded up to the nearest integer ## power of 2 by zero padding. FFT length is adjusted ## after addition of padding by explicit Nfft argument. ## The default is to use exactly the FFT and window/ ## segment lengths specified in argument list. ## ## @item results ## specifies what results to return (in the order specified ## and as many as desired). ## ## 'power' calculate power spectral density of "x" ## ## 'cross' calculate cross spectral density of "x" and "y" ## ## 'trans' calculate transfer function of a system with ## input "x" and output "y" ## ## 'coher' calculate coherence function of "x" and "y" ## ## 'ypower' calculate power spectral density of "y" ## ## The default is 'power', with argument "y" omitted. ## @end table ## ## RETURNED VALUES: ## ## If return values are not required by the caller, the results are ## plotted and nothing is returned. ## ## @table @asis ## @item spectra ## [real-or-complex matrix] columns of the matrix contain results ## in the same order as specified by "results" arguments. ## Each column contains one of the result vectors. ## ## @item Pxx_ci ## [real matrix] estimate of confidence interval for power ## spectral density of x. First column is the lower ## bound. Second column is the upper bound. ## ## @item freq ## [real column vector] frequency values ## @end table ## ## HINTS ## @enumerate ## @item EMPTY ARGS: ## if you don't want to use an optional argument you can leave it empty ## by writing its value as []. ## ## @item FOR BEGINNERS: ## The profusion of arguments may make pwelch difficult to use, and an ## unskilled user can easily produce a meaningless result or can easily ## mis-interpret the result. With real data "x" and sampling frequency ## "Fs", the easiest and best way for a beginner to use pwelch is ## probably "pwelch(x,[],[],[],Fs)". Use the "window" argument to ## control the length of the spectrum vector. For real data and integer ## scalar M, "pwelch(x,2*M,[],[],Fs)" gives an M+1 point spectrum. ## Run "demo pwelch" (octave only). ## ## @item WINDOWING FUNCTIONS: ## Without a window function, sharp spectral peaks can have strong ## sidelobes because the FFT of a data in a segment is in effect convolved ## with a rectangular window. A window function which tapers off ## (gradually) at the ends produces much weaker sidelobes in the FFT. ## Hann (hanning), hamming, bartlett, blackman, flattopwin etc are ## available as separate Matlab/sigproc or Octave functions. The sidelobes ## of the Hann window have a roll-off rate of 60dB/decade of frequency. ## The first sidelobe of the Hamming window is suppressed and is about 12dB ## lower than the first Hann sidelobe, but the roll-off rate is only ## 20dB/decade. You can inspect the FFT of a Hann window by plotting ## "abs(fft(postpad(hanning(256),4096,0)))". ## The default window is Hamming. ## ## @item ZERO PADDING: ## Zero-padding reduces the frequency step in the ## spectrum, and produces an artificially smoothed spectrum. For example, ## "Nfft=2*length(window)" gives twice as many frequency values, but ## adjacent PSD (power spectral density) values are not independent; ## adjacent PSD values are independent if "Nfft=length(window)", which is ## the default value of Nfft. ## ## @item REMOVING MEAN FROM SIGNAL: ## If the mean is not removed from the signal there is a large spectral ## peak at zero frequency and the sidelobes of this peak are likely to ## swamp the rest of the spectrum. For this reason, the default behavior ## is to remove the mean. However, the matlab pwelch does not do this. ## ## @item WARNING ON CONFIDENCE INTERVALS ## Confidence intervals are obtained by measuring the sample variance of ## the periodograms and assuming that the periodograms have a Gaussian ## probability distribution. This assumption is not accurate. If, for ## example, the data (x) is Gaussian, the periodogram has a Rayleigh ## distribution. However, the confidence intervals may still be useful. ## ## @item COMPATIBILITY WITH Matlab R11, R12, etc ## When used without the second data (y) argument, arguments are compatible ## with the pwelch of Matlab R12, R13, R14, 2006a and 2006b except that ## ## 1) overlap is expressed as a multiple of window length --- ## effect of overlap scales with window length ## ## 2) default values of length(window), Nfft and Fs are more sensible, and ## ## 3) Goertzel algorithm is not available so Nfft cannot be an array of ## frequencies as in Matlab 2006b. ## ## Pwelch has four persistent Matlab-compatibility levels. Calling pwelch ## with an empty first argument sets the order of arguments and defaults ## specified above in the USAGE and ARGUMENTS section of this documentation. ## @example ## prev_compat=pwelch([]); ## [Pxx,f]=pwelch(x,window,overlap,Nfft,Fs,conf,...); ## @end example ## Calling pwelch with a single string argument (as described below) gives ## compatibility with Matlab R11 or R12, or the R14 spectrum.welch ## defaults. The returned value is the PREVIOUS compatibility string. ## ## Matlab R11: For compatibility with the Matlab R11 pwelch: ## @example ## prev_compat=pwelch('R11-'); ## [Pxx,f]=pwelch(x,Nfft,Fs,window,overlap,conf,range,units); ## %% units of overlap are "number of samples" ## %% defaults: Nfft=min(length(x),256), Fs=2*pi, length(window)=Nfft, ## %% window=Hanning, do not detrend, ## %% N.B. "Sloppy" is not available. ## @end example ## ## Matlab R12: For compatibility with Matlab R12 to 2006a pwelch: ## @example ## prev_compat=pwelch('R12+'); ## [Pxx,f]=pwelch(x,window,overlap,nfft,Fs,...); ## %% units of overlap are "number of samples" ## %% defaults: length(window)==length(x)/8, window=Hamming, ## %% Nfft=max(256,NextPow2), Fs=2*pi, do not detrend ## %% NextPow2 is the next power of 2 greater than or equal to the ## %% window length. "Sloppy", "conf" are not available. Default ## %% window length gives very poor amplitude resolution. ## @end example ## ## To adopt defaults of the Matlab R14 "spectrum.welch" spectrum object ## associated "psd" method. ## @example ## prev_compat=pwelch('psd'); ## [Pxx,f] = pwelch(x,window,overlap,Nfft,Fs,conf,...); ## %% overlap is expressed as a percentage of window length, ## %% defaults: length(window)==64, Nfft=max(256,NextPow2), Fs=2*pi ## %% do not detrend ## %% NextPow2 is the next power of 2 greater than or equal to the ## %% window length. "Sloppy" is not available. ## %% Default window length gives coarse frequency resolution. ## @end example ## @end enumerate ## ## REFERENCES ## ## [1] Peter D. Welch (June 1967): ## "The use of fast Fourier transform for the estimation of power spectra: ## a method based on time averaging over short, modified periodograms." ## IEEE Transactions on Audio Electroacoustics, Vol AU-15(6), pp 70-73 ## ## [2] William H. Press and Saul A. Teukolsky and William T. Vetterling and ## Brian P. Flannery", ## "Numerical recipes in C, The art of scientific computing", 2nd edition, ## Cambridge University Press, 2002 --- Section 13.7. ## @end deftypefn function varargout = pwelch(x,varargin) ## ## COMPATIBILITY LEVEL ## Argument positions and defaults depend on compatibility level selected ## by calling pwelch without arguments or with a single string argument. ## native: compatib=1; prev_compat=pwelch(); prev_compat=pwelch([]); ## matlab R11: compatib=2; prev_compat=pwelch('R11-'); ## matlab R12: compatib=3; prev_compat=pwelch('R12+'); ## spectrum.welch defaults: compatib=4; prev_compat=pwelch('psd'); ## In each case, the returned value is the PREVIOUS compatibility string. ## compat_str = {[]; 'R11-'; 'R12+'; 'psd'}; persistent compatib; if ( isempty(compatib) || compatib<=0 || compatib>4 ) ## legal values are 1, 2, 3, 4 compatib = 1; endif if ( nargin <= 0 ) error( 'pwelch: Need at least 1 arg. Use "help pwelch".' ); elseif ( nargin==1 && (ischar(x) || isempty(x)) ) varargout{1} = compat_str{compatib}; if ( isempty(x) ) # native compatib = 1; elseif ( strcmp(x,'R11-') ) compatib = 2; elseif ( strcmp(x,'R12+') ) compatib = 3; elseif ( strcmp(x,'psd') ) compatib = 4; else error( 'pwelch: compatibility arg must be empty, R11-, R12+ or psd' ); endif ## return ## ## Check fixed argument elseif ( isempty(x) || ~isvector(x) ) error( 'pwelch: arg 1 (x) must be vector.' ); else ## force x to be COLUMN vector if ( size(x,1)==1 ) x=x(:); endif ## ## Look through all args to check if cross PSD, transfer function or ## coherence is required. If yes, the second arg is data vector "y". arg2_is_y = 0; x_len = length(x); nvarargin = length(varargin); for iarg=1:nvarargin arg = varargin{iarg}; if ( ~isempty(arg) && ischar(arg) && ... ( strcmp(arg,'cross') || strcmp(arg,'trans') || ... strcmp(arg,'coher') || strcmp(arg,'ypower') )) ## OK. Need "y". Grab it from 2nd arg. arg = varargin{1}; if ( nargin<2 || isempty(arg) || ~isvector(arg) || length(arg)~=x_len ) error( 'pwelch: arg 2 (y) must be vector, same length as x.' ); endif ## force COLUMN vector y = varargin{1}(:); arg2_is_y = 1; break; endif endfor ## ## COMPATIBILITY ## To select default argument values, "compatib" is used as an array index. ## Index values are 1=native, 2=R11, 3=R12, 4=spectrum.welch ## ## argument positions: ## arg_posn = varargin index of window, overlap, Nfft, Fs and conf ## args respectively, a value of zero ==>> arg does not exist arg_posn = [1 2 3 4 5; # native 3 4 1 2 5; # Matlab R11- pwelch 1 2 3 4 0; # Matlab R12+ pwelch 1 2 3 4 5]; # spectrum.welch defaults arg_posn = arg_posn(compatib,:) + arg2_is_y; ## ## SPECIFY SOME DEFAULT VALUES for (not all) optional arguments ## Use compatib as array index. ## Fs = sampling frequency Fs = [ 1.0 2*pi 2*pi 2*pi ]; Fs = Fs(compatib); ## plot_type: 1='plot'|'squared'; 5='db'|'dB' plot_type = [ 1 5 5 5 ]; plot_type = plot_type(compatib); ## rm_mean: 3='long-mean'; 0='no-strip'|'none' rm_mean = [ 3 0 0 0 ]; rm_mean = rm_mean(compatib); ## use max_overlap=x_len-1 because seg_len is not available yet ## units of overlap are different for each version: ## fraction, samples, or percent max_overlap = [ 0.95 x_len-1 x_len-1 95]; max_overlap = max_overlap(compatib); ## default confidence interval ## if there are more than 2 return values and if there is a "conf" arg conf = 0.95 * (nargout>2) * (arg_posn(5)>0); ## is_win = 0; # =0 means valid window arg is not provided yet Nfft = []; # default depends on segment length overlap = []; # WARNING: units can be #samples, fraction or percentage range = ~isreal(x) || ( arg2_is_y && ~isreal(y) ); is_sloppy = 0; n_results = 0; do_power = 0; do_cross = 0; do_trans = 0; do_coher = 0; do_ypower = 0; ## ## DECODE AND CHECK OPTIONAL ARGUMENTS end_numeric_args = 0; for iarg = 1+arg2_is_y:nvarargin arg = varargin{iarg}; if ( ischar(arg) ) ## first string arg ==> no more numeric args ## non-string args cannot follow a string arg end_numeric_args = 1; ## ## decode control-string arguments if ( strcmp(arg,'sloppy') ) is_sloppy = ~is_win || is_win==1; elseif ( strcmp(arg,'plot') || strcmp(arg,'squared') ) plot_type = 1; elseif ( strcmp(arg,'semilogx') ) plot_type = 2; elseif ( strcmp(arg,'semilogy') ) plot_type = 3; elseif ( strcmp(arg,'loglog') ) plot_type = 4; elseif ( strcmp(arg,'db') || strcmp(arg,'dB') ) plot_type = 5; elseif ( strcmp(arg,'half') || strcmp(arg,'onesided') ) range = 0; elseif ( strcmp(arg,'whole') || strcmp(arg,'twosided') ) range = 1; elseif ( strcmp(arg,'shift') || strcmp(arg,'centerdc') ) range = 2; elseif ( strcmp(arg,'long-mean') ) rm_mean = 3; elseif ( strcmp(arg,'linear') ) rm_mean = 2; elseif ( strcmp(arg,'short') || strcmp(arg,'mean') ) rm_mean = 1; elseif ( strcmp(arg,'no-strip') || strcmp(arg,'none') ) rm_mean = 0; elseif ( strcmp(arg, 'power' ) ) if ( ~do_power ) n_results = n_results+1; do_power = n_results; endif elseif ( strcmp(arg, 'cross' ) ) if ( ~do_cross ) n_results = n_results+1; do_cross = n_results; endif elseif ( strcmp(arg, 'trans' ) ) if ( ~do_trans ) n_results = n_results+1; do_trans = n_results; endif elseif ( strcmp(arg, 'coher' ) ) if ( ~do_coher ) n_results = n_results+1; do_coher = n_results; endif elseif ( strcmp(arg, 'ypower' ) ) if ( ~do_ypower ) n_results = n_results+1; do_ypower = n_results; endif else error( 'pwelch: string arg %d illegal value: %s', iarg+1, arg ); endif ## end of processing string args ## elseif ( end_numeric_args ) if ( ~isempty(arg) ) ## found non-string arg after a string arg ... oops error( 'pwelch: control arg must be string' ); endif ## ## first 4 optional arguments are numeric -- in fixed order ## ## deal with "Fs" and "conf" first because empty arg is a special default ## -- "Fs" arg -- sampling frequency elseif ( iarg == arg_posn(4) ) if ( isempty(arg) ) Fs = 1; elseif ( ~isscalar(arg) || ~isreal(arg) || arg<0 ) error( 'pwelch: arg %d (Fs) must be real scalar >0', iarg+1 ); else Fs = arg; endif ## ## -- "conf" arg -- confidence level ## guard against the "it cannot happen" iarg==0 elseif ( arg_posn(5) && iarg == arg_posn(5) ) if ( isempty(arg) ) conf = 0.95; elseif ( ~isscalar(arg) || ~isreal(arg) || arg < 0.0 || arg >= 1.0 ) error( 'pwelch: arg %d (conf) must be real scalar, >=0, <1',iarg+1 ); else conf = arg; endif ## ## skip all empty args from this point onward elseif ( isempty(arg) ) 1; ## ## -- "window" arg -- window function elseif ( iarg == arg_posn(1) ) if ( isscalar(arg) ) is_win = 1; elseif ( isvector(arg) ) is_win = length(arg); if ( size(arg,2)>1 ) # vector must be COLUMN vector arg = arg(:); endif else is_win = 0; endif if ( ~is_win ) error( 'pwelch: arg %d (window) must be scalar or vector', iarg+1 ); elseif ( is_win==1 && ( ~isreal(arg) || fix(arg)~=arg || arg<=3 ) ) error( 'pwelch: arg %d (window) must be integer >3', iarg+1 ); elseif ( is_win>1 && ( ~isreal(arg) || any(arg<0) ) ) error( 'pwelch: arg %d (window) vector must be real and >=0',iarg+1); endif window = arg; is_sloppy = 0; ## ## -- "overlap" arg -- segment overlap elseif ( iarg == arg_posn(2) ) if (~isscalar(arg) || ~isreal(arg) || arg<0 || arg>max_overlap ) error( 'pwelch: arg %d (overlap) must be real from 0 to %f', ... iarg+1, max_overlap ); endif overlap = arg; ## ## -- "Nfft" arg -- FFT length elseif ( iarg == arg_posn(3) ) if ( ~isscalar(arg) || ~isreal(arg) || fix(arg)~=arg || arg<0 ) error( 'pwelch: arg %d (Nfft) must be integer >=0', iarg+1 ); endif Nfft = arg; ## else error( 'pwelch: arg %d must be string', iarg+1 ); endif endfor if ( conf>0 && (n_results && ~do_power ) ) error('pwelch: can give confidence interval for x power spectrum only' ); endif ## ## end DECODE AND CHECK OPTIONAL ARGUMENTS. ## ## SETUP REMAINING PARAMETERS ## default action is to calculate power spectrum only if ( ~n_results ) n_results = 1; do_power = 1; endif need_Pxx = do_power || do_trans || do_coher; need_Pxy = do_cross || do_trans || do_coher; need_Pyy = do_coher || do_ypower; log_two = log(2); nearly_one = 0.99999999999; ## ## compatibility-options ## provides exact compatibility with Matlab R11 or R12 ## ## Matlab R11 compatibility if ( compatib==2 ) if ( isempty(Nfft) ) Nfft = min( 256, x_len ); endif if ( is_win > 1 ) seg_len = min( length(window), Nfft ); window = window(1:seg_len); else if ( is_win ) ## window arg is scalar seg_len = window; else seg_len = Nfft; endif ## make Hann window (don't depend on sigproc) xx = seg_len - 1; window = 0.5 - 0.5 * cos( (2*pi/xx)*[0:xx].' ); endif ## ## Matlab R12 compatibility elseif ( compatib==3 ) if ( is_win > 1 ) ## window arg provides window function seg_len = length(window); else ## window arg does not provide window function; use Hamming if ( is_win ) ## window arg is scalar seg_len = window; else ## window arg not available; use R12 default, 8 windows ## ignore overlap arg; use overlap=50% -- only choice that makes sense ## this is the magic formula for 8 segments with 50% overlap seg_len = fix( (x_len-3)*2/9 ); endif ## make Hamming window (don't depend on sigproc) xx = seg_len - 1; window = 0.54 - 0.46 * cos( (2*pi/xx)*[0:xx].' ); endif if ( isempty(Nfft) ) Nfft = max( 256, 2^ceil(log(seg_len)*nearly_one/log_two) ); endif ## ## Matlab R14 psd(spectrum.welch) defaults elseif ( compatib==4 ) if ( is_win > 1 ) ## window arg provides window function seg_len = length(window); else ## window arg does not provide window function; use Hamming if ( is_win ) ## window arg is scalar seg_len = window; else ## window arg not available; use default seg_len = 64 seg_len = 64; endif ## make Hamming window (don't depend on sigproc) xx = seg_len - 1; window = 0.54 - 0.46 * cos( (2*pi/xx)*[0:xx].' ); endif ## Now we know segment length, ## so we can set default overlap as number of samples if ( ~isempty(overlap) ) overlap = fix(seg_len * overlap / 100 ); endif if ( isempty(Nfft) ) Nfft = max( 256, 2^ceil(log(seg_len)*nearly_one/log_two) ); endif ## ## default compatibility level else # if ( compatib==1 ) ## calculate/adjust segment length, window function if ( is_win > 1 ) ## window arg provides window function seg_len = length(window); else ## window arg does not provide window function; use Hamming if ( is_win ) # window arg is scalar seg_len = window; else ## window arg not available; use default length: ## = sqrt(length(x)) rounded up to nearest integer power of 2 if ( isempty(overlap) ) overlap=0.5; endif seg_len = 2 ^ ceil( log(sqrt(x_len/(1-overlap)))*nearly_one/log_two ); endif ## make Hamming window (don't depend on sigproc) xx = seg_len - 1; window = 0.54 - 0.46 * cos( (2*pi/xx)*[0:xx].' ); endif ## Now we know segment length, ## so we can set default overlap as number of samples if ( ~isempty(overlap) ) overlap = fix(seg_len * overlap); endif ## ## calculate FFT length if ( isempty(Nfft) ) Nfft = seg_len; endif if ( is_sloppy ) Nfft = 2 ^ ceil( log(Nfft) * nearly_one / log_two ); endif endif ## end of compatibility options ## ## minimum FFT length is seg_len Nfft = max( Nfft, seg_len ); ## Mean square of window is required for normalizing PSD amplitude. win_meansq = (window.' * window) / seg_len; ## ## Set default or check overlap. if ( isempty(overlap) ) overlap = fix(seg_len /2); elseif ( overlap >= seg_len ) error( 'pwelch: arg (overlap=%d) too big. Must be 0 ) Vxx = xx; else Vxx = []; endif n_ffts = 0; for start_seg = [1:seg_len-overlap:x_len-seg_len+1] end_seg = start_seg+seg_len-1; ## Don't truncate/remove the zero padding in xx and yy if ( need_Pxx || need_Pxy ) if ( rm_mean==1 ) # remove mean from segment xx(1:seg_len) = window .* ( ... x(start_seg:end_seg) - sum(x(start_seg:end_seg)) / seg_len); elseif ( rm_mean == 2 ) # remove linear trend from segment xx(1:seg_len) = window .* detrend( x(start_seg:end_seg) ); else # rm_mean==0 or 3 xx(1:seg_len) = window .* x(start_seg:end_seg); endif fft_x = fft(xx); endif if ( need_Pxy || need_Pyy ) if ( rm_mean==1 ) # remove mean from segment yy(1:seg_len) = window .* ( ... y(start_seg:end_seg) - sum(y(start_seg:end_seg)) / seg_len); elseif ( rm_mean == 2 ) # remove linear trend from segment yy(1:seg_len) = window .* detrend( y(start_seg:end_seg) ); else # rm_mean==0 or 3 yy(1:seg_len) = window .* y(start_seg:end_seg); endif fft_y = fft(yy); endif if ( need_Pxx ) ## force Pxx to be real; pgram = periodogram pgram = real(fft_x .* conj(fft_x)); Pxx = Pxx + pgram; ## sum of squared periodograms is required for confidence interval if ( conf>0 ) Vxx = Vxx + pgram .^2; endif endif if ( need_Pxy ) ## Pxy (cross power spectrum) is complex. Do not force to be real. Pxy = Pxy + fft_y .* conj(fft_x); endif if ( need_Pyy ) ## force Pyy to be real Pyy = Pyy + real(fft_y .* conj(fft_y)); endif n_ffts = n_ffts +1; endfor ## ## Calculate confidence interval ## -- incorrectly assumes that the periodogram has Gaussian probability ## distribution (actually, it has a single-sided (e.g. exponential) ## distribution. ## Sample variance of periodograms is (Vxx-Pxx.^2/n_ffts)/(n_ffts-1). ## This method of calculating variance is more susceptible to round-off ## error, but is quicker, and for double-precision arithmetic and the ## inherently noisy periodogram (variance==mean^2), it should be OK. if ( conf>0 && need_Pxx ) if ( n_ffts<2 ) Vxx = zeros(Nfft,1); else ## Should use student distribution here (for unknown variance), but tinv ## is not a core Matlab function (is in statistics toolbox. Grrr) Vxx = (erfinv(conf)*sqrt(2*n_ffts/(n_ffts-1))) * sqrt(Vxx-Pxx.^2/n_ffts); endif endif ## ## Convert two-sided spectra to one-sided spectra (if range == 0). ## For one-sided spectra, contributions from negative frequencies are added ## to the positive side of the spectrum -- but not at zero or Nyquist ## (half sampling) frequencies. This keeps power equal in time and spectral ## domains, as required by Parseval theorem. ## if ( range == 0 ) if ( ~ rem(Nfft,2) ) # one-sided, Nfft is even psd_len = Nfft/2+1; if ( need_Pxx ) Pxx = Pxx(1:psd_len) + [0; Pxx(Nfft:-1:psd_len+1); 0]; if ( conf>0 ) Vxx = Vxx(1:psd_len) + [0; Vxx(Nfft:-1:psd_len+1); 0]; endif endif if ( need_Pxy ) Pxy = Pxy(1:psd_len) + conj([0; Pxy(Nfft:-1:psd_len+1); 0]); endif if ( need_Pyy ) Pyy = Pyy(1:psd_len) + [0; Pyy(Nfft:-1:psd_len+1); 0]; endif else # one-sided, Nfft is odd psd_len = (Nfft+1)/2; if ( need_Pxx ) Pxx = Pxx(1:psd_len) + [0; Pxx(Nfft:-1:psd_len+1)]; if ( conf>0 ) Vxx = Vxx(1:psd_len) + [0; Vxx(Nfft:-1:psd_len+1)]; endif endif if ( need_Pxy ) Pxy = Pxy(1:psd_len) + conj([0; Pxy(Nfft:-1:psd_len+1)]); endif if ( need_Pyy ) Pyy = Pyy(1:psd_len) + [0; Pyy(Nfft:-1:psd_len+1)]; endif endif else # two-sided (and shifted) psd_len = Nfft; endif ## end MAIN CALCULATIONS ## ## SCALING AND OUTPUT ## Put all results in matrix, one row per spectrum ## Pxx, Pxy, Pyy are sums of periodograms, so "n_ffts" ## in the scale factor converts them into averages spectra = zeros(psd_len,n_results); spect_type = zeros(n_results,1); scale = n_ffts * seg_len * Fs * win_meansq; if ( do_power ) spectra(:,do_power) = Pxx / scale; spect_type(do_power) = 1; if ( conf>0 ) Vxx = [Pxx-Vxx Pxx+Vxx]/scale; endif endif if ( do_cross ) spectra(:,do_cross) = Pxy / scale; spect_type(do_cross) = 2; endif if ( do_trans ) spectra(:,do_trans) = Pxy ./ Pxx; spect_type(do_trans) = 3; endif if ( do_coher ) ## force coherence to be real spectra(:,do_coher) = real(Pxy .* conj(Pxy)) ./ Pxx ./ Pyy; spect_type(do_coher) = 4; endif if ( do_ypower ) spectra(:,do_ypower) = Pyy / scale; spect_type(do_ypower) = 5; endif freq = [0:psd_len-1].' * ( Fs / Nfft ); ## ## range='shift': Shift zero-frequency to the middle if ( range == 2 ) len2 = fix((Nfft+1)/2); spectra = [ spectra(len2+1:Nfft,:); spectra(1:len2,:)]; freq = [ freq(len2+1:Nfft)-Fs; freq(1:len2)]; if ( conf>0 ) Vxx = [ Vxx(len2+1:Nfft,:); Vxx(1:len2,:)]; endif endif ## ## RETURN RESULTS or PLOT if ( nargout>=2 && conf>0 ) varargout{2} = Vxx; endif if ( nargout>=(2+(conf>0)) ) ## frequency is 2nd or 3rd return value, ## depends on if 2nd is confidence interval varargout{2+(conf>0)} = freq; endif if ( nargout>=1 ) varargout{1} = spectra; else ## ## Plot the spectra if there are no return variables. plot_title=['power spectrum x '; 'cross spectrum '; 'transfer function'; 'coherence '; 'power spectrum y ' ]; for ii = 1: n_results if ( conf>0 && spect_type(ii)==1 ) Vxxxx = Vxx; else Vxxxx = []; endif if ( n_results > 1 ) figure(); endif if ( plot_type == 1 ) plot(freq,[abs(spectra(:,ii)) Vxxxx]); elseif ( plot_type == 2 ) semilogx(freq,[abs(spectra(:,ii)) Vxxxx]); elseif ( plot_type == 3 ) semilogy(freq,[abs(spectra(:,ii)) Vxxxx]); elseif ( plot_type == 4 ) loglog(freq,[abs(spectra(:,ii)) Vxxxx]); elseif ( plot_type == 5 ) # db ylabel( 'amplitude (dB)' ); plot(freq,[10*log10(abs(spectra(:,ii))) 10*log10(abs(Vxxxx))]); endif title( char(plot_title(spect_type(ii),:)) ); ylabel( 'amplitude' ); ## Plot phase of cross spectrum and transfer function if ( spect_type(ii)==2 || spect_type(ii)==3 ) figure(); if ( plot_type==2 || plot_type==4 ) semilogx(freq,180/pi*angle(spectra(:,ii))); else plot(freq,180/pi*angle(spectra(:,ii))); endif title( char(plot_title(spect_type(ii),:)) ); ylabel( 'phase' ); endif endfor endif endif endfunction %!demo %! a = [ 1.0 -1.6216505 1.1102795 -0.4621741 0.2075552 -0.018756746 ]; %! white = rand(1,16384); %! signal = detrend(filter(0.70181,a,white)); %! % frequency shift by modulating with exp(j.omega.t) %! skewed = signal.*exp(2*pi*i*2/25*[1:16384]); %! compat = pwelch ([]); %! hold on; %! pwelch(signal); %! pwelch(skewed); %! pwelch(signal,'shift','semilogy'); %! pwelch (compat); %! hold off; %!demo %! Fs = 25; %! a = [ 1.0 -1.6216505 1.1102795 -0.4621741 0.2075552 -0.018756746 ]; %! white = rand(1,16384); %! signal = detrend(filter(0.70181,a,white)); %! % frequency shift by modulating with exp(j.omega.t) %! skewed = signal.*exp(2*pi*i*2/25*[1:16384]); %! compat = pwelch ([]); %! pwelch(skewed,[],[],[],Fs,'shift','semilogy'); %! pwelch(skewed,[],[],[],Fs,0.95,'shift','semilogy'); %! pwelch('R12+'); %! pwelch(signal,'squared'); %! pwelch (compat); %!demo %! a = [ 1.0 -1.6216505 1.1102795 -0.4621741 0.2075552 -0.018756746 ]; %! white = rand(1,16384); %! signal = detrend(filter(0.70181,a,white)); %! compat = pwelch ([]); %! pwelch(signal,3640,[],4096,2*pi,[],'no-strip'); %! pwelch (compat); %!demo %! a = [ 1.0 -1.6216505 1.1102795 -0.4621741 0.2075552 -0.018756746 ]; %! white = rand(1,16384); %! signal = detrend(filter(0.70181,a,white)); %! compat = pwelch ([]); %! hold on; %! pwelch(signal,[],[],[],2*pi,0.95,'no-strip'); %! pwelch(signal,64,[],[],2*pi,'no-strip'); %! pwelch(signal,64,[],256,2*pi,'no-strip'); %! pwelch (compat); %! hold off; %!demo %! a = [ 1.0 -1.6216505 1.1102795 -0.4621741 0.2075552 -0.018756746 ]; %! white = rand(1,16384); %! signal = detrend(filter(0.70181,a,white)); %! compat = pwelch ('psd'); %! pwelch(signal,'squared'); %! pwelch({}); %! pwelch(white,signal,'trans','coher','short') %! pwelch (compat); signal-1.4.5/inst/pyulear.m0000644000000000000000000001162714456505401014013 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[psd,f_out] =} pyulear(x,poles,freq,Fs,range,method,plot_type) ## Calculates a Yule-Walker autoregressive (all-pole) model of the data "x" ## and computes the power spectrum of the model. ## ## This is a wrapper for functions "aryule" and "ar_psd" which perform the ## argument checking. ## ## See "help aryule" and "help ar_psd" for further details. ## ## ARGUMENTS: ## ## All but the first two arguments are optional and may be empty. ## @table @asis ## @item x ## [vector] sampled data ## ## @item poles ## [integer scalar] required number of poles of the AR model ## ## @item freq ## [real vector] frequencies at which power spectral density ## is calculated ## ## [integer scalar] number of uniformly distributed frequency ## values at which spectral density is calculated. ## [default=256] ## ## @item Fs ## [real scalar] sampling frequency (Hertz) [default=1] ## @end table ## ## CONTROL-STRING ARGUMENTS -- each of these arguments is a character string. ## ## Control-string arguments can be in any order after the other arguments. ## ## @table @asis ## @item range ## 'half', 'onesided' : frequency range of the spectrum is ## from zero up to but not including sample_f/2. Power ## from negative frequencies is added to the positive ## side of the spectrum. ## ## 'whole', 'twosided' : frequency range of the spectrum is ## -sample_f/2 to sample_f/2, with negative frequencies ## stored in "wrap around" order after the positive ## frequencies; e.g. frequencies for a 10-point 'twosided' ## spectrum are 0 0.1 0.2 0.3 0.4 0.5 -0.4 -0.3 -0.2 -0.1 ## ## 'shift', 'centerdc' : same as 'whole' but with the first half ## of the spectrum swapped with second half to put the ## zero-frequency value in the middle. (See "help ## fftshift". If "freq" is vector, 'shift' is ignored. ## ## If model coefficients "ar_coeffs" are real, the default ## range is 'half', otherwise default range is 'whole'. ## ## @item method ## 'fft': use FFT to calculate power spectrum. ## ## 'poly': calculate power spectrum as a polynomial of 1/z ## N.B. this argument is ignored if the "freq" argument is a ## vector. The default is 'poly' unless the "freq" ## argument is an integer power of 2. ## ## @item plot_type ## 'plot', 'semilogx', 'semilogy', 'loglog', 'squared' or 'db': ## specifies the type of plot. The default is 'plot', which ## means linear-linear axes. 'squared' is the same as 'plot'. ## 'dB' plots "10*log10(psd)". This argument is ignored and a ## spectrum is not plotted if the caller requires a returned ## value. ## @end table ## ## RETURNED VALUES: ## ## If return values are not required by the caller, the spectrum ## is plotted and nothing is returned. ## ## @table @asis ## @item psd ## [real vector] power-spectrum estimate ## @item f_out ## [real vector] frequency values ## @end table ## ## HINTS ## ## This function is a wrapper for aryule and ar_psd. ## ## See "help aryule", "help ar_psd". ## @end deftypefn function [psd,f_out]=pyulear(x,poles,varargin) ## if ( nargin<2 ) error( 'pburg: need at least 2 args. Use "help pburg"' ); endif ## [ar_coeffs,residual,k]=aryule(x,poles); if ( nargout==0 ) ar_psd(ar_coeffs,residual,varargin{:}); elseif ( nargout==1 ) psd = ar_psd(ar_coeffs,residual,varargin{:}); elseif ( nargout>=2 ) [psd,f_out] = ar_psd(ar_coeffs,residual,varargin{:}); endif endfunction %!demo %! a = [1.0 -1.6216505 1.1102795 -0.4621741 0.2075552 -0.018756746]; %! Fs = 25; %! n = 16384; %! signal = detrend (filter (0.70181, a, rand (1, n))); %! % frequency shift by modulating with exp(j.omega.t) %! skewed = signal .* exp (2*pi*i*2/Fs*[1:n]); %! hold on; %! pyulear (signal, 3, [], Fs); %! pyulear (signal, 4, [], Fs, "whole"); %! pyulear (signal, 5, 128, Fs, "shift", "semilogy"); %! pyulear (skewed, 7, 128, Fs, "shift", "semilogy"); %! user_freq = [-0.2:0.02:0.2]*Fs; %! pyulear (skewed, 7, user_freq, Fs, "semilogy"); %! hold off; signal-1.4.5/inst/qp_kaiser.m0000644000000000000000000000552614456505401014311 0ustar0000000000000000## Copyright (C) 2002 AndrĂ© Carezia ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} qp_kaiser (@var{nb}, @var{at}) ## @deftypefnx {Function File} {} qp_kaiser (@var{nb}, @var{at}, @var{linear}) ## ## Computes a finite impulse response (FIR) filter for use with a ## quasi-perfect reconstruction polyphase-network filter bank. This ## version utilizes a Kaiser window to shape the frequency response of ## the designed filter. Tha number nb of bands and the desired ## attenuation at in the stop-band are given as parameters. ## ## The Kaiser window is multiplied by the ideal impulse response ## h(n)=a.sinc(a.n) and converted to its minimum-phase version by means ## of a Hilbert transform. ## ## By using a third non-null argument, the minimum-phase calculation is ## omitted at all. ## @end deftypefn function h = qp_kaiser (nb, at, linear = 0) if (nargin < 2) print_usage; elseif !(isscalar (nb) && (nb == round(nb)) && (nb >= 0)) error ("qp_kaiser: nb has to be a positive integer"); elseif !(isscalar (at) && (at == real (at))) error ("qp_kaiser: at has to be a real constant"); endif ## Bandwidth bandwidth = pi/nb; ## Attenuation correction (empirically ## determined by M. Gerken ## ) corr = (1.4+0.6*(at-20)/80)^(20/at); at = corr * at; ## size of window (rounded to next odd ## integer) N = (at - 8) / (2.285*bandwidth); M = fix(N/2); N = 2*M + 1; ## Kaiser window if (at>50) beta = 0.1102 * (at - 8.7); elseif (at>21) beta = 0.5842 * (at - 21)^0.4 + 0.07886 * (at - 21); else beta = 0; endif w = kaiser(N,beta); ## squared in freq. domain wsquared = conv(w,w); ## multiplied by ideal lowpass filter n = -(N-1):(N-1); hideal = 1/nb * sinc(n/nb); hcomp = wsquared .* hideal; ## extract square-root of response and ## compute minimum-phase version Ndft = 2^15; Hsqr = sqrt(abs(fft(hcomp,Ndft))); if (linear) h = real(ifft(Hsqr)); h = h(2:N); h = [fliplr(h) h(1) h]; else Hmin = Hsqr .* exp(-j*imag(hilbert(log(Hsqr)))); h = real(ifft(Hmin)); h = h(1:N); endif ## truncate and fix amplitude scale ## (H(0)=1) h = h / sum(h); endfunction signal-1.4.5/inst/rceps.m0000644000000000000000000001131714456505401013442 0ustar0000000000000000## Copyright (C) 1999 Paul Kienzle ## Copyright (C) 2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{y}, @var{ym}] =} rceps (@var{x}) ## Return the cepstrum of the signal @var{x}. ## ## If @var{x} is a matrix, return the cepstrum of each column. ## ## If called with two output arguments, the minimum phase reconstruction of ## the signal @var{x} is returned in @var{ym}. ## ## For example: ## ## @example ## @group ## f0 = 70; Fs = 10000; # 100 Hz fundamental, 10kHz sampling rate ## a = poly (0.985 * exp (1i * pi * [0.1, -0.1, 0.3, -0.3])); # two formants ## s = 0.005 * randn (1024, 1); # Noise excitation signal ## s(1:Fs/f0:length(s)) = 1; # Impulse glottal wave ## x = filter (1, a, s); # Speech signal ## [y, ym] = rceps (x .* hanning (1024)); ## @end group ## @end example ## ## Reference: @cite{Programs for Digital Signal Processing}, IEEE Press, ## John Wiley & Sons, New York, 1979. ## @end deftypefn function [y, ym] = rceps (x) if (nargin != 1) print_usage (); endif f = abs (fft (x)); if (any (f == 0)) error ("rceps: the spectrum of x contains zeros, unable to compute real cepstrum"); endif y = real (ifft (log (f))); if (nargout == 2) n = length (x); if (rows (x) == 1) if (rem (n,2) == 1) ym = [y(1), 2 * y(2:fix (n/2) + 1), zeros(1, fix (n/2))]; else ym = [y(1), 2 * y(2:n/2), y(n/2 + 1), zeros(1, n/2 - 1)]; endif else if (rem (n,2) == 1) ym = [y(1,:); 2 * y(2:fix (n/2) + 1,:); zeros(fix (n/2), columns (y))]; else ym = [y(1,:); 2 * y(2:n/2,:); y(n/2 + 1,:); zeros(n/2 - 1, columns (y))]; endif endif ym = real (ifft (exp (fft (ym)))); endif endfunction %!test %! ## accepts matrices %! x = randn (32, 3); %! [y, xm] = rceps (x); %! ## check the mag-phase response of the reproduction %! hx = fft (x); %! hxm = fft (xm); %! assert (abs (hx), abs (hxm), 200*eps); # good magnitude response match %! ## FIXME: test for minimum phase? Stop using random datasets! %! #assert (arg (hx) != arg (hxm)); # phase mismatch %!test %! ## accepts column and row vectors %! x = randn (256, 1); %! [y, xm] = rceps (x); %! [yt, xmt] = rceps (x.'); %! assert (yt.', y, 1e-14); %! assert (xmt.', xm, 1e-14); ## Test that an odd-length input produces an odd-length output %!test %! x = randn (33, 4); %! [y, xm] = rceps (x); %! assert (size (y), size (x)); %! assert (size (xm), size (x)); ## Test input validation %!error rceps %!error rceps (1, 2) %!error rceps (0) %!error rceps (zeros (10, 1)) %!demo %! f0 = 70; Fs = 10000; # 100 Hz fundamental, 10 kHz sampling rate %! a = real (poly (0.985 * exp (1i * pi * [0.1, -0.1, 0.3, -0.3]))); # two formants %! s = 0.05 * randn (1024, 1); # Noise excitation signal %! s(floor (1:Fs/f0:length (s))) = 1; # Impulse glottal wave %! x = filter (1, a, s); # Speech signal in x %! [y, xm] = rceps (x); # cepstrum and minimum phase x %! [hx, w] = freqz (x, 1, [], Fs); %! hxm = freqz (xm); %! figure (1); %! subplot (311); %! len = 1000 * fix (min (length (x), length (xm)) / 1000); %! plot ([0:len-1] * 1000 / Fs, x(1:len), "b;signal;", ... %! [0:len-1] * 1000 / Fs, xm(1:len), "g;reconstruction;"); %! ylabel ("Amplitude"); %! xlabel ("Time (ms)"); %! subplot (312); %! axis ("ticy"); %! plot (w, log (abs (hx)), ";magnitude;", ... %! w, log (abs (hxm)), ";reconstruction;"); %! xlabel ("Frequency (Hz)"); %! subplot (313); %! axis ("on"); %! plot (w, unwrap (arg (hx)) / (2 * pi), ";phase;", ... %! w, unwrap (arg (hxm)) / (2 * pi), ";reconstruction;"); %! xlabel ("Frequency (Hz)"); %! len = 1000 * fix (length (y) / 1000); %! figure (2); %! plot ([0:len-1] * 1000 / Fs, y(1:len), ";cepstrum;"); %! ylabel ("Amplitude"); %! xlabel ("Quefrency (ms)"); %! %------------------------------------------------------------- %! % confirm the magnitude spectrum is identical in the signal %! % and the reconstruction and that there are peaks in the %! % cepstrum at 14 ms intervals corresponding to an F0 of 70 Hz. signal-1.4.5/inst/rectpuls.m0000644000000000000000000000463314456505401014172 0ustar0000000000000000## Copyright (C) 2000 Paul Kienzle ## Copyright (C) 2018-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} rectpuls (@var{t}) ## @deftypefnx {Function File} {@var{y} =} rectpuls (@var{t}, @var{w}) ## Generate a rectangular pulse over the interval [-@var{w}/2,@var{w}/2), ## sampled at times @var{t}. This is useful with the function @code{pulstran} ## for generating a series of pulses. ## ## Example: ## @example ## @group ## fs = 11025; # arbitrary sample rate ## f0 = 100; # pulse train sample rate ## w = 0.3/f0; # pulse width 3/10th the distance between pulses ## plot (pulstran (0:1/fs:4/f0, 0:1/f0:4/f0, "rectpuls", w)); ## @end group ## @end example ## ## @seealso{gauspuls, pulstran, tripuls} ## @end deftypefn function y = rectpuls (t, w = 1) if (nargin < 1 || nargin > 2) print_usage (); endif if (! isreal (w) || ! isscalar (w)) error ("rectpuls: W must be a real scalar"); endif y = zeros (size (t)); idx = find ((t >= -w/2) & (t < w/2)); y(idx) = 1; endfunction %!demo %! fs = 11025; # arbitrary sample rate %! f0 = 100; # pulse train sample rate %! w = 0.3/f0; # pulse width 1/10th the distance between pulses %! x = pulstran (0:1/fs:4/f0, 0:1/f0:4/f0, "rectpuls", w); %! plot ([0:length(x)-1]*1000/fs, x); %! xlabel ("Time (ms)"); %! ylabel ("Amplitude"); %! title ("Rectangular pulse train of 3 ms pulses at 10 ms intervals"); %!assert (rectpuls ([]), []) %!assert (rectpuls ([], 0.1), []) %!assert (rectpuls (zeros (10, 1)), ones (10, 1)) %!assert (rectpuls (-1:1), [0, 1, 0]) %!assert (rectpuls (-5:5, 9), [0, ones(1,9), 0]) %!assert (rectpuls (0:1/100:0.3, 0.1), rectpuls ([0:1/100:0.3]', 0.1)') ## Test input validation %!error rectpuls () %!error rectpuls (1, 2, 3) %!error rectpuls (1, 2j) signal-1.4.5/inst/rectwin.m0000644000000000000000000000260014456505401013774 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} rectwin (@var{m}) ## Return the filter coefficients of a rectangular window of length @var{m}. ## @seealso{boxcar, hamming, hanning} ## @end deftypefn function w = rectwin (m) if (nargin != 1) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("rectwin: M must be a positive integer"); endif w = ones (m, 1); endfunction %!assert (rectwin (1), 1) %!assert (rectwin (2), ones (2, 1)) %!assert (rectwin (100), ones (100, 1)) %% Test input validation %!error rectwin () %!error rectwin (0.5) %!error rectwin (-1) %!error rectwin (ones (1, 4)) %!error rectwin (1, 2) signal-1.4.5/inst/resample.m0000644000000000000000000001236514456505401014142 0ustar0000000000000000## Copyright (C) 2008 Eric Chassande-Mottin, CNRS (France) ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{y}, @var{h}] =} resample (@var{x}, @var{p}, @var{q}) ## @deftypefnx {Function File} {@var{y} =} resample (@var{x}, @var{p}, @var{q}, @var{h}) ## Change the sample rate of @var{x} by a factor of @var{p}/@var{q}. This is ## performed using a polyphase algorithm. The impulse response @var{h} of ## the antialiasing filter is either specified or either designed with a ## Kaiser-windowed sinecard. ## ## Ref [1] J. G. Proakis and D. G. Manolakis, ## Digital Signal Processing: Principles, Algorithms, and Applications, ## 4th ed., Prentice Hall, 2007. Chap. 6 ## ## Ref [2] A. V. Oppenheim, R. W. Schafer and J. R. Buck, ## Discrete-time signal processing, Signal processing series, ## Prentice-Hall, 1999 ## @end deftypefn function [y, h] = resample( x, p, q, h ) if nargchk(3,4,nargin) print_usage; elseif any([p q]<=0) || any([p q]~=floor([p q])), error("resample.m: p and q must be positive integers"); endif ## simplify decimation and interpolation factors great_common_divisor=gcd(p,q); if (great_common_divisor>1) p = double (p) / double (great_common_divisor); q = double (q) / double (great_common_divisor); else p = double (p); q = double (q); endif ## filter design if required if (nargin < 4) ## properties of the antialiasing filter log10_rejection = -3.0; stopband_cutoff_f = 1 / (2 * max (p, q)); roll_off_width = stopband_cutoff_f / 10.0; ## determine filter length ## use empirical formula from [2] Chap 7, Eq. (7.63) p 476 rejection_dB = -20.0*log10_rejection; L = ceil((rejection_dB-8.0) / (28.714 * roll_off_width)); ## ideal sinc filter t=(-L:L)'; ideal_filter=2*p*stopband_cutoff_f*sinc(2*stopband_cutoff_f*t); ## determine parameter of Kaiser window ## use empirical formula from [2] Chap 7, Eq. (7.62) p 474 if ((rejection_dB>=21) && (rejection_dB<=50)) beta = 0.5842 * (rejection_dB-21.0)^0.4 + 0.07886 * (rejection_dB-21.0); elseif (rejection_dB>50) beta = 0.1102 * (rejection_dB-8.7); else beta = 0.0; endif ## apodize ideal filter response h=kaiser(2*L+1,beta).*ideal_filter; endif ## check if input is a row vector isrowvector=false; if ((rows(x)==1) && (columns(x)>1)) x=x(:); isrowvector=true; endif ## check if filter is a vector if ~isvector(h) error("resample.m: the filter h should be a vector"); endif Lx = rows(x); Lh = length(h); L = ( Lh - 1 )/2.0; Ly = ceil(Lx*p/q); ## pre and postpad filter response nz_pre = floor(q-mod(L,q)); hpad = prepad(h,Lh+nz_pre); offset = floor((L+nz_pre)/q); nz_post = 0; while ceil( ( (Lx-1)*p + nz_pre + Lh + nz_post )/q ) - offset < Ly nz_post++; endwhile hpad = postpad(hpad,Lh + nz_pre + nz_post); ## filtering xfilt = upfirdn(x,hpad,p,q); y = xfilt(offset+1:offset+Ly,:); if isrowvector, y=y.'; endif endfunction %!test %! N=512; %! p=3; q=5; %! r=p/q; %! NN=ceil(r*N); %! t=0:N-1; %! tt=0:NN-1; %! err=zeros(N/2,1); %! for n = 0:N/2-1, %! phi0=2*pi*rand; %! f0=n/N; %! x=sin(2*pi*f0*t' + phi0); %! [y,h]=resample(x,p,q); %! xx=sin(2*pi*f0/r*tt' + phi0); %! t0=ceil((length(h)-1)/2/q); %! idx=t0+1:NN-t0; %! err(n+1)=max(abs(y(idx)-xx(idx))); %! endfor; %! rolloff=.1; %! rejection=10^-3; %! idx_inband=1:ceil((1-rolloff/2)*r*N/2)-1; %! assert(max(err(idx_inband)) ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{r}, @var{p}, @var{f}, @var{m}] =} residued (@var{b}, @var{a}) ## Compute the partial fraction expansion (PFE) of filter ## @math{H(z) = B(z)/A(z)}. In the usual PFE function @code{residuez}, the ## IIR part (poles @var{p} and residues @var{r}) is driven @emph{in parallel} ## with the FIR part (@var{f}). In this variant, the IIR part is driven by ## the @emph{output} of the FIR part. This structure can be more accurate in ## signal modeling applications. ## ## INPUTS: ## @var{b} and @var{a} are vectors specifying the digital filter ## @math{H(z) = B(z)/A(z)}. See @code{help filter} for documentation of the ## @var{b} and @var{a} filter coefficients. ## ## RETURNED: ## @itemize ## @item @var{r} = column vector containing the filter-pole residues ## @item @var{p} = column vector containing the filter poles ## @item @var{f} = row vector containing the FIR part, if any ## @item @var{m} = column vector of pole multiplicities ## @end itemize ## ## EXAMPLES: ## @example ## See @code{test residued verbose} to see a number of examples. ## @end example ## ## For the theory of operation, see ## @indicateurl{http://ccrma.stanford.edu/~jos/filters/residued.html} ## ## @seealso{residue, residued} ## @end deftypefn function [r, p, f, m] = residued(b, a, toler) ## RESIDUED - return residues, poles, and FIR part of B(z)/A(z) ## ## Let nb = length(b), na = length(a), and N=na-1 = no. of poles. ## If nb ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{r}, @var{p}, @var{f}, @var{m}] =} residuez (@var{b}, @var{a}) ## Compute the partial fraction expansion of filter @math{H(z) = B(z)/A(z)}. ## ## INPUTS: ## @var{b} and @var{a} are vectors specifying the digital filter ## @math{H(z) = B(z)/A(z)}. See @code{help filter} for documentation of the ## @var{b} and @var{a} filter coefficients. ## ## RETURNED: ## @itemize ## @item @var{r} = column vector containing the filter-pole residues ## @item @var{p} = column vector containing the filter poles ## @item @var{f} = row vector containing the FIR part, if any ## @item @var{m} = column vector of pole multiplicities ## @end itemize ## ## EXAMPLES: ## @example ## See @code{test residuez verbose} to see a number of examples. ## @end example ## ## For the theory of operation, see ## @indicateurl{http://ccrma.stanford.edu/~jos/filters/residuez.html} ## ## @seealso{residue, residued} ## @end deftypefn function [r, p, f, m] = residuez(B, A, tol) ## RESIDUEZ - return residues, poles, and FIR part of B(z)/A(z) ## ## Let nb = length(b), na = length(a), and N=na-1 = no. of poles. ## If nb= na, the FIR part f will not be empty. ## Let M = nb-na+1 = order of f = length(f)-1). Then the returned filter is ## ## H(z) = f(1) + f(2)/z + f(3)/z^2 + ... + f(M+1)/z^M + R(z) ## ## where R(z) is the parallel one-pole filter bank defined above. ## Note, in particular, that the impulse-response of the one-pole ## filter bank is in parallel with that of the the FIR part. This can ## be wasteful when matching the initial impulse response is important, ## since F(z) can already match the first N terms of the impulse ## response. To obtain a decomposition in which the impulse response of ## the IIR part R(z) starts after that of the FIR part F(z), use RESIDUED. ## ## J.O. Smith, 9/19/05 if nargin==3 warning("tolerance ignored"); endif NUM = B(:)'; DEN = A(:)'; ## Matlab's residue does not return m (since it is implied by p): [r,p,f,m]=residue(conj(fliplr(NUM)),conj(fliplr(DEN))); p = 1 ./ p; r = r .* ((-p) .^m); f = conj(fliplr(f)); endfunction %!test %! B=[1 -2 1]; A=[1 -1]; %! [r,p,f,m] = residuez(B,A); %! assert(r,0,100*eps); %! assert(p,1,100*eps); %! assert(f,[1 -1],100*eps); %! assert(m,1,100*eps); %!test %! B=1; A=[1 -1j]; %! [r,p,f,m] = residuez(B,A); %! assert(r,1,100*eps); %! assert(p,1j,100*eps); %! assert(f,[],100*eps); %! assert(m,1,100*eps); %!test %! B=1; A=[1 -1 .25]; %! [r,p,f,m] = residuez(B,A); %! [rs,is] = sort(r); %! assert(rs,[0;1],1e-7); %! assert(p(is),[0.5;0.5],1e-8); %! assert(f,[],100*eps); %! assert(m(is),[1;2],100*eps); %!test %! B=1; A=[1 -0.75 .125]; %! [r,p,f,m] = residuez(B,A); %! [rs,is] = sort(r); %! assert(rs,[-1;2],100*eps); %! assert(p(is),[0.25;0.5],100*eps); %! assert(f,[],100*eps); %! assert(m(is),[1;1],100*eps); %!test %! B=[1,6,2]; A=[1,-2,1]; %! [r,p,f,m] = residuez(B,A); %! [rs,is] = sort(r); %! assert(rs,[-10;9],1e-7); %! assert(p(is),[1;1],1e-8); %! assert(f,[2],100*eps); %! assert(m(is),[1;2],100*eps); %!test %! B=[6,2]; A=[1,-2,1]; %! [r,p,f,m] = residuez(B,A); %! [rs,is] = sort(r); %! assert(rs,[-2;8],1e-7); %! assert(p(is),[1;1],1e-8); %! assert(f,[],100*eps); %! assert(m(is),[1;2],100*eps); %!test %! B=[1,6,6,2]; A=[1,-2,1]; %! [r,p,f,m] = residuez(B,A); %! [rs,is] = sort(r); %! assert(rs,[-24;15],2e-7); %! assert(p(is),[1;1],1e-8); %! assert(f,[10,2],100*eps); %! assert(m(is),[1;2],100*eps); %!test %! B=[1,6,6,2]; A=[1,-(2+j),(1+2j),-j]; %! [r,p,f,m] = residuez(B,A); %! [rs,is] = sort(r); %! assert(rs,[-2+2.5j;7.5+7.5j;-4.5-12j],1E-6); %! assert(p(is),[1j;1;1],1E-6); %! assert(f,-2j,1E-6); %! assert(m(is),[1;2;1],1E-6); %!test %! B=[1,0,1]; A=[1,0,0,0,0,-1]; %! [r,p,f,m] = residuez(B,A); %! [as,is] = sort(angle(p)); %! rise = [ ... %! 0.26180339887499 - 0.19021130325903i; ... %! 0.03819660112501 + 0.11755705045849i; ... %! 0.4; ... %! 0.03819660112501 - 0.11755705045849i; ... %! 0.26180339887499 + 0.19021130325903i;]; %! pise = [ ... %! -0.80901699437495 - 0.58778525229247i; ... %! 0.30901699437495 - 0.95105651629515i; ... %! 1; ... %! 0.30901699437495 + 0.95105651629515i; ... %! -0.80901699437495 + 0.58778525229247i]; %! assert(r(is),rise,100*eps); %! assert(p(is),pise,100*eps); %! assert(f,[],100*eps); %! assert(m,[1;1;1;1;1],100*eps); %!test # bug 57359 %! [r,p,k] = residuez([1 1 1.5 .5],[1 1.5 .5]); %! [rs,is] = sort(r); %! assert(r(is), [-1; 2], 100*eps); %! assert(p(is), [-0.5; -1], 100*eps); %! assert(k, [0 1], 100*eps); signal-1.4.5/inst/rms.m0000644000000000000000000000344214456505401013127 0ustar0000000000000000## Copyright (C) 2015 Andreas Weber ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} rms (@var{x}) ## @deftypefnx {Function File} {@var{y} =} rms (@var{x}, @var{dim}) ## Compute the root-mean-square (RMS) of the vector @var{x}. ## ## The root-mean-square is defined as ## ## @tex ## $$ {\rm rms}(x) = {\sqrt{\sum_{i=1}^N {x_i}^2 \over N}} $$ ## @end tex ## @ifnottex ## ## @example ## rms (@var{x}) = SQRT (1/N SUM_i @var{x}(i)^2) ## @end example ## ## @end ifnottex ## If @var{x} is a matrix, compute the root-mean-square for each column and ## return them in a row vector. ## ## If the optional argument @var{dim} is given, operate along this dimension. ## @seealso{mean, meansq, peak2rms, rssq, sumsq} ## @end deftypefn function y = rms (varargin) if (nargin < 1 || nargin > 2) print_usage (); endif y = sqrt (meansq (varargin{:})); endfunction %!assert (rms (0), 0) %!assert (rms (1), 1) %!assert (rms ([1 2 -1]), sqrt (2)) %!assert (rms ([1 2 -1]'), sqrt (2)) %!assert (rms ([1 2], 3), [1 2]) ## Test input validation %!error rms () %!error rms (1, 2, 3) %!error rms (1, 1.5) %!error rms (1, -1) signal-1.4.5/inst/rssq.m0000644000000000000000000000337014456505401013316 0ustar0000000000000000## Copyright (C) 2018-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} rssq (@var{x}) ## @deftypefnx {Function File} {@var{y} =} rssq (@var{x}, @var{dim}) ## Compute the root-sum-of-squares (RSS) of the vector @var{x}. ## ## The root-sum-of-squares is defined as ## ## @tex ## $$ {\rm rssq}(x) = {\sqrt{\sum_{i=1}^N {x_i}^2}} $$ ## @end tex ## @ifnottex ## ## @example ## rssq (@var{x}) = SQRT (SUM_i @var{x}(i)^2) ## @end example ## ## @end ifnottex ## If @var{x} is a matrix, compute the root-sum-of-squares for each column and ## return them in a row vector. ## ## If the optional argument @var{dim} is given, operate along this dimension. ## @seealso{mean, meansq, sumsq, rms} ## @end deftypefn function y = rssq (varargin) if (nargin < 1 || nargin > 2) print_usage (); endif y = sqrt (sumsq (varargin{:})); endfunction %!assert (rssq ([]), 0) %!assert (rssq ([1 2 -1]), sqrt (6)) %!assert (rssq ([1 2 -1]'), sqrt (6)) %!assert (rssq ([1 2], 3), [1 2]) ## Test input validation %!error rssq () %!error rssq (1, 2, 3) %!error rssq (1, 1.5) %!error rssq (1, -1) signal-1.4.5/inst/sampled2continuous.m0000644000000000000000000000271214456505401016163 0ustar0000000000000000## Copyright (C) 2009 Muthiah Annamalai ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{xt} =} sampled2continuous (@var{xn}, @var{T}, @var{t}) ## ## Calculate the x(t) reconstructed ## from samples x[n] sampled at a rate 1/T samples ## per unit time. ## ## t is all the instants of time when you need x(t) ## from x[n]; this time is relative to x[0] and not ## an absolute time. ## ## This function can be used to calculate sampling rate ## effects on aliasing, actual signal reconstruction ## from discrete samples. ## @end deftypefn function xt = sampled2continuous( xn , T, t ) if ( nargin < 3 ) print_usage() endif N = length( xn ); xn = reshape( xn, N, 1 ); [TT,tt]= meshgrid(T*(0:N-1)',t); S = sinc((tt -TT)./T); xt = S*xn; return endfunction signal-1.4.5/inst/sawtooth.m0000644000000000000000000000401214456505401014170 0ustar0000000000000000## Copyright (C) 2007 Juan Aguado ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} sawtooth (@var{t}) ## @deftypefnx {Function File} {@var{y} =} sawtooth (@var{t}, @var{width}) ## Generates a sawtooth wave of period @code{2 * pi} with limits @code{+1/-1} ## for the elements of @var{t}. ## ## @var{width} is a real number between @code{0} and @code{1} which specifies ## the point between @code{0} and @code{2 * pi} where the maximum is. The ## function increases linearly from @code{-1} to @code{1} in @code{[0, 2 * ## pi * @var{width}]} interval, and decreases linearly from @code{1} to ## @code{-1} in the interval @code{[2 * pi * @var{width}, 2 * pi]}. ## ## If @var{width} is 0.5, the function generates a standard triangular wave. ## ## If @var{width} is not specified, it takes a value of 1, which is a standard ## sawtooth function. ## @end deftypefn function y = sawtooth (t,width) if (nargin < 1 || nargin > 2) print_usage (); endif if (nargin == 1) width = 1; else if (width < 0 || width > 1 || ! isreal (width)) error ("width must be a real number between 0 and 1."); endif endif t = mod (t / (2 * pi), 1); y = zeros (size (t)); if (width != 0) y (t < width) = 2 * t (t < width) / width - 1; endif if (width != 1) y( t >= width) = -2 * (t (t >= width) - width) / (1 - width) + 1; endif endfunction signal-1.4.5/inst/schtrig.m0000644000000000000000000001007014456505401013764 0ustar0000000000000000## Copyright (C) 2012 Juan Pablo Carbajal ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {@var{v} =} schtrig (@var{x},@var{lvl},@var{rst}=1) ## @deftypefnx {[@var{v},@var{rng}] =} schtrig (@dots{}) ## Implements a multisignal Schmitt trigger with levels @var{lvl}. ## ## The triger works along the first dimension of the 2-dimensional array @var{x}. ## It compares each column in @var{x} to the levels in @var{lvl}, when the ## value is higher @code{max (@var{lvl})} the output @var{v} is high (i.e. 1); when the ## value is below @code{min (@var{lvl})} the output is low (i.e. 0); and when ## the value is between the two levels the output retains its value. ## ## The threshold levels are passed in the array @var{lvl}. If this is a scalar, ## the thresholds are symmetric around 0, i.e. @code{[-lvl lvl]}. ## ## The second output argument stores the ranges in which the output is high, so ## the indexes @var{rng(1,i):rng(2,i)} point to the i-th segment of 1s in @var{v}. ## See @code{clustersegment} for a detailed explanation. ## ## The function conserves the state of the trigger across calls (persistent variable). ## If the reset flag is active, i.e. @code{@var{rst}== true}, then the state of ## the trigger for all signals is set to the low state (i.e. 0). ## ## Example: ## @example ## x = [0 0.5 1 1.5 2 1.5 1.5 1.2 1 0 0].'; ## y = schtrig (x, [1.3 1.6]); ## disp ([x y]); ## 0.0 0 ## 0.5 0 ## 1.0 0 ## 1.5 0 ## 2.0 1 ## 1.5 1 ## 1.5 1 ## 1.2 0 ## 1.0 0 ## 0.0 0 ## 0.0 0 ## @end example ## ## Run @code{demo schtrig} to see further examples. ## ## @seealso{clustersegment} ## @end deftypefn function [v rg] = schtrig (x, lvl, rst = true) if (length (ndims (x)) > 2) error ('Octave:invalid-input-arg', 'The input should be two dimensional.'); endif if (length (ndims (lvl)) > 2) error ('Octave:invalid-input-arg', 'Only a maximum of two threshold levels accepted.'); endif [nT nc] = size (x); persistent st0; if (rst || isempty (st0)) st0 = zeros (1,nc); endif if (length(lvl) == 1) lvl = abs (lvl) .* [1 -1]; else lvl = sort (lvl,'descend'); endif v = NA (nT, nc); v(1,:) = st0; ## Signal is above up level up = x > lvl(1); v(up) = 1; ## Signal is below down level dw = x < lvl(2); v(dw) = 0; ## Resolve intermediate states ## Find data between the levels idx = isnan (v); ranges = clustersegment (idx'); if (nc == 1) ranges = {ranges}; endif for i=1:nc ## Record the state at the beginning of the interval between levels if (!isempty (ranges{i})) prev = ranges{i}(1,:)-1; prev(prev<1) = 1; st0 = v(prev,i); ## Copy the initial state to the interval ini_idx = ranges{i}(1,:); end_idx = ranges{i}(2,:); for j =1:length(ini_idx) v(ini_idx(j):end_idx(j),i) = st0(j); endfor endif endfor st0 = v(end,:); endfunction %!demo %! t = linspace(0,1,100)'; %! x = sin (2*pi*2*t) + sin (2*pi*5*t).*[0.8 0.3]; %! %! lvl = [0.8 0.25]'; %! v = schtrig (x,lvl); %! %! subplot(2,1,1) %! h = plot (t, x(:,1), t, v(:,1)); %! set (h, 'linewidth',2); %! line([0; 1],lvl([1; 1]),'color','g'); %! line([0;1],lvl([2;2]),'color','k') %! axis tight %! %! subplot(2,1,2) %! h = plot (t, x(:,2), t, v(:,2)); %! set (h,'linewidth',2); %! line([0; 1],lvl([1; 1]),'color','g'); %! line([0;1],lvl([2;2]),'color','k') %! axis tight # TODO add tests signal-1.4.5/inst/sftrans.m0000644000000000000000000001727414456505401014016 0ustar0000000000000000## Copyright (C) 1999-2001 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{Sz}, @var{Sp}, @var{Sg}] =} sftrans (@var{Sz}, @var{Sp}, @var{Sg}, @var{W}, @var{stop}) ## ## Transform band edges of a generic lowpass filter (cutoff at W=1) ## represented in splane zero-pole-gain form. W is the edge of the ## target filter (or edges if band pass or band stop). Stop is true for ## high pass and band stop filters or false for low pass and band pass ## filters. Filter edges are specified in radians, from 0 to pi (the ## nyquist frequency). ## ## Theory: Given a low pass filter represented by poles and zeros in the ## splane, you can convert it to a low pass, high pass, band pass or ## band stop by transforming each of the poles and zeros individually. ## The following table summarizes the transformation: ## ## @example ## Transform Zero at x Pole at x ## ---------------- ------------------------- ------------------------ ## Low Pass zero: Fc x/C pole: Fc x/C ## S -> C S/Fc gain: C/Fc gain: Fc/C ## ---------------- ------------------------- ------------------------ ## High Pass zero: Fc C/x pole: Fc C/x ## S -> C Fc/S pole: 0 zero: 0 ## gain: -x gain: -1/x ## ---------------- ------------------------- ------------------------ ## Band Pass zero: b +- sqrt(b^2-FhFl) pole: b +- sqrt(b^2-FhFl) ## S^2+FhFl pole: 0 zero: 0 ## S -> C -------- gain: C/(Fh-Fl) gain: (Fh-Fl)/C ## S(Fh-Fl) b=x/C (Fh-Fl)/2 b=x/C (Fh-Fl)/2 ## ---------------- ------------------------- ------------------------ ## Band Stop zero: b +- sqrt(b^2-FhFl) pole: b +- sqrt(b^2-FhFl) ## S(Fh-Fl) pole: +-sqrt(-FhFl) zero: +-sqrt(-FhFl) ## S -> C -------- gain: -x gain: -1/x ## S^2+FhFl b=C/x (Fh-Fl)/2 b=C/x (Fh-Fl)/2 ## ---------------- ------------------------- ------------------------ ## Bilinear zero: (2+xT)/(2-xT) pole: (2+xT)/(2-xT) ## 2 z-1 pole: -1 zero: -1 ## S -> - --- gain: (2-xT)/T gain: (2-xT)/T ## T z+1 ## ---------------- ------------------------- ------------------------ ## @end example ## ## where C is the cutoff frequency of the initial lowpass filter, Fc is ## the edge of the target low/high pass filter and [Fl,Fh] are the edges ## of the target band pass/stop filter. With abundant tedious algebra, ## you can derive the above formulae yourself by substituting the ## transform for S into H(S)=S-x for a zero at x or H(S)=1/(S-x) for a ## pole at x, and converting the result into the form: ## ## @example ## H(S)=g prod(S-Xi)/prod(S-Xj) ## @end example ## ## The transforms are from the references. The actual pole-zero-gain ## changes I derived myself. ## ## Please note that a pole and a zero at the same place exactly cancel. ## This is significant for High Pass, Band Pass and Band Stop filters ## which create numerous extra poles and zeros, most of which cancel. ## Those which do not cancel have a "fill-in" effect, extending the ## shorter of the sets to have the same number of as the longer of the ## sets of poles and zeros (or at least split the difference in the case ## of the band pass filter). There may be other opportunistic ## cancellations but I will not check for them. ## ## Also note that any pole on the unit circle or beyond will result in ## an unstable filter. Because of cancellation, this will only happen ## if the number of poles is smaller than the number of zeros and the ## filter is high pass or band pass. The analytic design methods all ## yield more poles than zeros, so this will not be a problem. ## ## References: ## ## Proakis & Manolakis (1992). Digital Signal Processing. New York: ## Macmillan Publishing Company. ## @end deftypefn function [Sz, Sp, Sg] = sftrans(Sz, Sp, Sg, W, stop) if (nargin != 5) print_usage; endif C = 1; p = length(Sp); z = length(Sz); if z > p || p == 0 error("sftrans: must have at least as many poles as zeros in s-plane"); endif if length(W)==2 Fl = W(1); Fh = W(2); if stop ## ---------------- ------------------------- ------------------------ ## Band Stop zero: b ± sqrt(b^2-FhFl) pole: b ± sqrt(b^2-FhFl) ## S(Fh-Fl) pole: ±sqrt(-FhFl) zero: ±sqrt(-FhFl) ## S -> C -------- gain: -x gain: -1/x ## S^2+FhFl b=C/x (Fh-Fl)/2 b=C/x (Fh-Fl)/2 ## ---------------- ------------------------- ------------------------ if (isempty(Sz)) Sg = Sg * real (1./ prod(-Sp)); elseif (isempty(Sp)) Sg = Sg * real(prod(-Sz)); else Sg = Sg * real(prod(-Sz)/prod(-Sp)); endif b = (C*(Fh-Fl)/2)./Sp; Sp = [b+sqrt(b.^2-Fh*Fl), b-sqrt(b.^2-Fh*Fl)]; extend = [sqrt(-Fh*Fl), -sqrt(-Fh*Fl)]; if isempty(Sz) Sz = [extend(1+rem([1:2*p],2))]; else b = (C*(Fh-Fl)/2)./Sz; Sz = [b+sqrt(b.^2-Fh*Fl), b-sqrt(b.^2-Fh*Fl)]; if (p > z) Sz = [Sz, extend(1+rem([1:2*(p-z)],2))]; endif endif else ## ---------------- ------------------------- ------------------------ ## Band Pass zero: b ± sqrt(b^2-FhFl) pole: b ± sqrt(b^2-FhFl) ## S^2+FhFl pole: 0 zero: 0 ## S -> C -------- gain: C/(Fh-Fl) gain: (Fh-Fl)/C ## S(Fh-Fl) b=x/C (Fh-Fl)/2 b=x/C (Fh-Fl)/2 ## ---------------- ------------------------- ------------------------ Sg = Sg * (C/(Fh-Fl))^(z-p); b = Sp*((Fh-Fl)/(2*C)); Sp = [b+sqrt(b.^2-Fh*Fl), b-sqrt(b.^2-Fh*Fl)]; if isempty(Sz) Sz = zeros(1,p); else b = Sz*((Fh-Fl)/(2*C)); Sz = [b+sqrt(b.^2-Fh*Fl), b-sqrt(b.^2-Fh*Fl)]; if (p>z) Sz = [Sz, zeros(1, (p-z))]; endif endif endif else Fc = W; if stop ## ---------------- ------------------------- ------------------------ ## High Pass zero: Fc C/x pole: Fc C/x ## S -> C Fc/S pole: 0 zero: 0 ## gain: -x gain: -1/x ## ---------------- ------------------------- ------------------------ if (isempty(Sz)) Sg = Sg * real (1./ prod(-Sp)); elseif (isempty(Sp)) Sg = Sg * real(prod(-Sz)); else Sg = Sg * real(prod(-Sz)/prod(-Sp)); endif Sp = C * Fc ./ Sp; if isempty(Sz) Sz = zeros(1,p); else Sz = [C * Fc ./ Sz]; if (p > z) Sz = [Sz, zeros(1,p-z)]; endif endif else ## ---------------- ------------------------- ------------------------ ## Low Pass zero: Fc x/C pole: Fc x/C ## S -> C S/Fc gain: C/Fc gain: Fc/C ## ---------------- ------------------------- ------------------------ Sg = Sg * (C/Fc)^(z-p); Sp = Fc * Sp / C; Sz = Fc * Sz / C; endif endif endfunction signal-1.4.5/inst/sgolay.m0000644000000000000000000001042614456505401013624 0ustar0000000000000000## Copyright (C) 2001 Paul Kienzle ## Copyright (C) 2004 Pascal Dupuis ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{f} =} sgolay (@var{p}, @var{n}) ## @deftypefnx {Function File} {@var{f} =} sgolay (@var{p}, @var{n}, @var{m}) ## @deftypefnx {Function File} {@var{f} =} sgolay (@var{p}, @var{n}, @var{m}, @var{ts}) ## Computes the filter coefficients for all Savitzsky-Golay smoothing ## filters of order p for length n (odd). m can be used in order to ## get directly the mth derivative. In this case, ts is a scaling factor. ## ## The early rows of F smooth based on future values and later rows ## smooth based on past values, with the middle row using half future ## and half past. In particular, you can use row i to estimate x(k) ## based on the i-1 preceding values and the n-i following values of x ## values as y(k) = F(i,:) * x(k-i+1:k+n-i). ## ## Normally, you would apply the first (n-1)/2 rows to the first k ## points of the vector, the last k rows to the last k points of the ## vector and middle row to the remainder, but for example if you were ## running on a realtime system where you wanted to smooth based on the ## all the data collected up to the current time, with a lag of five ## samples, you could apply just the filter on row n-5 to your window ## of length n each time you added a new sample. ## ## Reference: Numerical recipes in C. p 650 ## ## @seealso{sgolayfilt} ## @end deftypefn ## Based on smooth.m by E. Farhi function F = sgolay (p, n, m = 0, ts = 1) if (nargin < 2 || nargin > 4) print_usage; elseif rem(n,2) != 1 error ("sgolay needs an odd filter length n"); elseif p >= n error ("sgolay needs filter length n larger than polynomial order p"); else if length(m) > 1, error("weight vector unimplemented"); endif ## Construct a set of filters from complete causal to completely ## noncausal, one filter per row. For the bulk of your data you ## will use the central filter, but towards the ends you will need ## a filter that doesn't go beyond the end points. F = zeros (n, n); k = floor (n/2); for row = 1:k+1 ## Construct a matrix of weights Cij = xi ^ j. The points xi are ## equally spaced on the unit grid, with past points using negative ## values and future points using positive values. C = ( [(1:n)-row]'*ones(1,p+1) ) .^ ( ones(n,1)*[0:p] ); ## A = pseudo-inverse (C), so C*A = I; this is constructed from the SVD A = pinv(C); ## Take the row of the matrix corresponding to the derivative ## you want to compute. F(row,:) = A(1+m,:); endfor ## The filters shifted to the right are symmetric with those to the left. F(k+2:n,:) = (-1)^m*F(k:-1:1,n:-1:1); endif F = F * ( prod(1:m) / (ts^m) ); endfunction %!test %! N=2^12; %! t=[0:N-1]'/N; %! dt=t(2)-t(1); %! w = 2*pi*50; %! offset = 0.5; # 50 Hz carrier %! # exponential modulation and its derivatives %! d = 1+exp(-3*(t-offset)); %! dd = -3*exp(-3*(t-offset)); %! d2d = 9*exp(-3*(t-offset)); %! d3d = -27*exp(-3*(t-offset)); %! # modulated carrier and its derivatives %! x = d.*sin(w*t); %! dx = dd.*sin(w*t) + w*d.*cos(w*t); %! d2x = (d2d-w^2*d).*sin(w*t) + 2*w*dd.*cos(w*t); %! d3x = (d3d-3*w^2*dd).*sin(w*t) + (3*w*d2d-w^3*d).*cos(w*t); %! %! y = sgolayfilt(x,sgolay(8,41,0,dt)); %! assert(norm(y-x)/norm(x),0,5e-6); %! %! y = sgolayfilt(x,sgolay(8,41,1,dt)); %! assert(norm(y-dx)/norm(dx),0,5e-6); %! %! y = sgolayfilt(x,sgolay(8,41,2,dt)); %! assert(norm(y-d2x)/norm(d2x),0,1e-5); %! %! y = sgolayfilt(x,sgolay(8,41,3,dt)); %! assert(norm(y-d3x)/norm(d3x),0,1e-4); signal-1.4.5/inst/sgolayfilt.m0000644000000000000000000001161314456505401014502 0ustar0000000000000000## Copyright (C) 2001 Paul Kienzle ## Copyright (C) 2004 Pascal Dupuis ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} sgolayfilt (@var{x}) ## @deftypefnx {Function File} {@var{y} =} sgolayfilt (@var{x}, @var{p}) ## @deftypefnx {Function File} {@var{y} =} sgolayfilt (@var{x}, @var{p}, @var{n}) ## @deftypefnx {Function File} {@var{y} =} sgolayfilt (@var{x}, @var{p}, @var{n}, @var{m}) ## @deftypefnx {Function File} {@var{y} =} sgolayfilt (@var{x}, @var{p}, @var{n}, @var{m}, @var{ts}) ## @deftypefnx {Function File} {@var{y} =} sgolayfilt (@var{x}, @var{p}, @var{n}, @var{m}, @var{ts}) ## @deftypefnx {Function File} {@var{y} =} sgolayfilt (@var{x}, @var{f}) ## Smooth the data in x with a Savitsky-Golay smoothing filter of ## polynomial order p and length n, n odd, n > p. By default, p=3 ## and n=p+2 or n=p+3 if p is even. ## ## If @var{f} is given as a matrix, it is expected to be a filter as ## computed by @code{sgolay}. ## ## These filters are particularly good at preserving lineshape while ## removing high frequency squiggles. Particularly, compare a 5 sample ## averager, an order 5 butterworth lowpass filter (cutoff 1/3) and ## sgolayfilt(x, 3, 5), the best cubic estimated from 5 points: ## ## @example ## @group ## [b, a] = butter (5, 1/3); ## x = [zeros(1,15), 10*ones(1,10), zeros(1,15)]; ## plot (sgolayfilt (x), "r;sgolayfilt;", ... ## filtfilt (ones (1,5)/5, 1, x), "g;5 sample average;", ... ## filtfilt (b, a, x), "c;order 5 butterworth;", ... ## x, "+b;original data;"); ## @end group ## @end example ## ## @seealso{sgolay} ## @end deftypefn ## FIXME: Patch filter.cc so that it accepts matrix arguments function y = sgolayfilt (x, p = 3, n, m = 0, ts = 1) if nargin < 1 || nargin > 5 print_usage; endif if (nargin >= 3) F = sgolay(p, n, m, ts); elseif (prod(size(p)) == 1) n = p+3-rem(p,2); F = sgolay(p, n); else F = p; n = size(F,1); if (size(F,1) != size(F,2)) error("sgolayfilt(x,F): F is not a Savitzsky-Golay filter set"); endif endif transpose = (size(x,1) == 1); if (transpose) x = x.'; endif; len = size(x,1); if (len < n) error("sgolayfilt: insufficient data for filter"); endif ## The first k rows of F are used to filter the first k points ## of the data set based on the first n points of the data set. ## The last k rows of F are used to filter the last k points ## of the data set based on the last n points of the dataset. ## The remaining data is filtered using the central row of F. ## As the filter coefficients are used in the reverse order of what ## seems the logical notation, reverse F(k+1, :) so that antisymmetric ## sequences are used with the right sign. k = floor(n/2); z = filter(F(k+1,n:-1:1), 1, x); y = [ F(1:k,:)*x(1:n,:) ; z(n:len,:) ; F(k+2:n,:)*x(len-n+1:len,:) ]; if (transpose) y = y.'; endif endfunction %!demo %! [b, a] = butter(5,1/3); %! x=[zeros(1,15), 10*ones(1,10), zeros(1,15)]; %! subplot(121); %! plot(sgolayfilt(x),"r;sgolay(3,5);",... %! filtfilt(ones(1,5)/5,1,x),"g;5 sample average;",... %! filtfilt(b,a,x),"c;order 5 butterworth;",... %! x,"+b;original data;"); %! axis([1 40 -2 15]); %! title("boxcar"); %! %! x=x+randn(size(x))/2; %! subplot(122); %! plot(sgolayfilt(x,3,5),"r;sgolay(3,5);",... %! filtfilt(ones(1,5)/5,1,x),"g;5 sample average;",... %! filtfilt(b,a,x),"c;order 5 butterworth;",... %! x,"+b;original data;"); %! axis([1 40 -2 15]); %! title("boxcar+noise"); %!demo %! [b, a] = butter(5,1/3); %! t = 0:0.01:1.0; % 1 second sample %! x=cos(2*pi*t*3); % 3 Hz sinusoid %! subplot(121); %! plot(t,sgolayfilt(x,3,5),"r;sgolay(3,5);",... %! t,filtfilt(ones(1,5)/5,1,x),"g;5 sample average;",... %! t,filtfilt(b,a,x),"c;order 5 butterworth;",... %! t,x,"+b;original data;"); %! axis([0 1 -1.5 2.5]); %! title("sinusoid"); %! %! x=x+0.2*randn(size(x)); % signal+noise %! subplot(122); %! plot(t,sgolayfilt(x',3,5),"r;sgolay(3,5);",... %! t,filtfilt(ones(1,5)/5,1,x),"g;5 sample average;",... %! t,filtfilt(b,a,x),"c;order 5 butterworth;",... %! t,x,"+b;original data;"); %! axis([0 1 -1.5 2.5]); %! title("sinusoid+noise"); signal-1.4.5/inst/shanwavf.m0000644000000000000000000000240714456505401014143 0ustar0000000000000000## Copyright (C) 2007 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{psi}, @var{x}] =} shanwavf (@var{lb}, @var{ub}, @var{n}, @var{fb}, @var{fc}) ## Compute the Complex Shannon wavelet. ## @end deftypefn function [psi,x] = shanwavf (lb,ub,n,fb,fc) if (nargin < 5) print_usage; elseif (n <= 0 || floor(n) ~= n) error("n must be an integer strictly positive"); elseif (fc <= 0 || fb <= 0) error("fc and fb must be strictly positive"); endif x = linspace(lb,ub,n); psi = (fb.^0.5).*(sinc(fb.*x).*exp(2.*i.*pi.*fc.*x)); endfunction signal-1.4.5/inst/shiftdata.m0000644000000000000000000000457014456505401014300 0ustar0000000000000000## Copyright (C) 2014 Georgios Ouzounis ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{out perm shifts}] =} shiftdata (@var{in}) ## @deftypefnx {Function File} {[@var{out perm shifts}] =} shiftdata (@var{in}, @var{dim}) ## Shift data @var{in} to permute the dimension @var{dim} to the first column. ## @seealso{unshiftdata} ## @end deftypefn function [out, perm, shifts] = shiftdata (in, dim) if (nargin < 1 || nargin > 2) print_usage (); elseif (nargin == 1 || (nargin == 2 && isempty (dim))) idx = find (size (in) - 1); dim = idx(1); shiftsflag = true; else shiftsflag = false; endif if (dim != fix (dim)) error ("shiftdata: DIM must be an integer"); endif perm = [dim 1: (dim - 1) (dim + 1): (length (size (in)))]; out = permute (in, perm); if (shiftsflag == true) perm = []; shifts = dim - 1; else shifts = []; endif endfunction %!test %! X = [1 2 3; 4 5 6; 7 8 9]; %! [Y, perm, shifts] = shiftdata (X, 2); %! assert (Y, [1 4 7; 2 5 8; 3 6 9]); %! assert (perm, [2 1]); %!test %! X = [27 42 11; 63 48 5; 67 74 93]; %! X(:, :, 2) = [15 23 81; 34 60 28; 70 54 38]; %! [Y, perm, shifts] = shiftdata(X, 2); %! T = [27 63 67; 42 48 74; 11 5 93]; %! T(:, :, 2) = [15 34 70; 23 60 54; 81 28 38]; %! assert(Y, T); %! assert(perm, [2 1 3]); %!test %! X = fix (rand (4, 4, 4, 4) * 100); %! [Y, perm, shifts] = shiftdata (X, 3); %! T = 0; %! for i = 1:3 %! for j = 1:3 %! for k = 1:2 %! for l = 1:2 %! T = [T Y(k, i, j, l) - X(i, j, k ,l)]; %! endfor %! endfor %! endfor %! endfor %! assert (T, zeros (size (T))); ## Test input validation %!error shiftdata () %!error shiftdata (1, 2, 3) %!error shiftdata (1, 2.5) signal-1.4.5/inst/sigmoid_train.m0000644000000000000000000001135214456505401015155 0ustar0000000000000000## Copyright (C) 2011-2013 Juan Pablo Carbajal ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{y} @var{s}] =} sigmoid_train (@var{t}, @var{ranges}, @var{rc}) ## ## Evaluate a train of sigmoid functions at @var{t}. ## ## The number and duration of each sigmoid is determined from @var{ranges}. ## Each row of @var{ranges} represents a real interval, e.g. if sigmoid ## @code{i} starts at @code{t=0.1} and ends at @code{t=0.5}, then ## @code{@var{ranges}(i,:) = [0.1 0.5]}. ## The input @var{rc} is an array that defines the rising and falling time ## constants of each sigmoid. Its size must equal the size of @var{ranges}. ## ## The individual sigmoids are returned in @var{s}. The combined sigmoid train ## is returned in the vector @var{y} of length equal to @var{t}, and such that ## @code{Y = max (S)}. ## ## Run @code{demo sigmoid_train} to some examples of the use of this function. ## ## @end deftypefn function [envelope Y] = sigmoid_train (t, range, timeconstant) ## number of sigmoids nRanges = size (range, 1); ## Parse time constants if isscalar (timeconstant) ## All bumps have the same time constant and are symmetric timeconstant = timeconstant * ones (nRanges,2); elseif any (size(timeconstant) == [1 1]) && nRanges > 1 ## All bumps have different time constant but are symmetric if isrow (timeconstant) timeconstant = timeconstant.'; endif if size (timeconstant, 1) != nRanges error('signalError','Length of time constant must equal number of ranges.') endif timeconstant = repmat (timeconstant,1,2); endif ## Make sure t is horizontal flag_transposed = false; if iscolumn (t) t = t.'; flag_transposed = true; endif [ncol nrow] = size (t); ## Compute arguments of each sigmoid # T = repmat (t, nRanges, 1); # RC1 = repmat (timeconstant(:,1), 1, nrow); # RC2 = repmat (timeconstant(:,2), 1, nrow); # a_up = (repmat (range(:,1), 1 ,nrow) - T) ./ RC1; # a_dw = (repmat (range(:,2), 1 ,nrow) - T) ./ RC2; # Using broadcasting a_up = bsxfun (@rdivide, bsxfun (@minus, range(:,1), t), timeconstant(:,1)); a_dw = bsxfun (@rdivide, bsxfun (@minus, range(:,2), t), timeconstant(:,2)); ## Evaluate the sigmoids and mix them Y = 1 ./ ( 1 + exp (a_up) ) .* (1 - 1 ./ ( 1 + exp (a_dw) ) ); envelope = max(Y,[],1); if flag_transposed envelope = envelope.'; Y = Y.'; endif endfunction %!demo %! # Vectorized %! t = linspace (0, 2, 500); %! range = [0.1 0.4; 0.6 0.8; 1 2]; %! rc = [1e-2 1e-3; 1e-3 2e-2; 2e-2 1e-2]; %! y = sigmoid_train (t, range, rc); %! for i=1:3 %! patch ([range(i,[2 2]) range(i,[1 1])], [0 1 1 0],... %! 'facecolor', [1 0.8 0.8],'edgecolor','none'); %! endfor %! hold on; plot (t, y, 'b;Sigmoid train;','linewidth',2); hold off %! xlabel('time'); ylabel('S(t)') %! title ('Vectorized use of sigmoid train') %! axis tight %! #------------------------------------------------------------------------- %! # The colored regions show the limits defined in range. %!demo %! # Varaible amplitude %! t = linspace (0, 2, 500); %! range = [0.1 0.4; 0.6 0.8; 1 2]; %! rc = [1e-2 1e-3; 1e-3 2e-2; 2e-2 1e-2]; %! amp = [4 2 3]; %! [~, S] = sigmoid_train (t, range, rc); %! y = amp * S; %! h = plot (t, y, '-b', t, S, '-'); %! set (h(1), "linewidth", 2); %! legend (h(1:2), {"Sigmoid train", "Components"}); %! xlabel('time'); ylabel('signal') %! title ('Varying amplitude sigmoid train') %! axis tight %!demo %! # On demand %! t = linspace(0,2,200).'; %! ran = [0.5 1; 1.5 1.7]; %! rc = 3e-2; %! dxdt = @(x_,t_) [ x_(2); sigmoid_train(t_, ran, rc) ]; %! y = lsode(dxdt,[0 0],t); %! for i=1:2 %! patch ([ran(i,[2 2]) ran(i,[1 1])], [0 1 1 0],... %! 'facecolor', [1 0.8 0.8],'edgecolor','none'); %! endfor %! hold on; plot (t, y(:,2), 'b;Speed;','linewidth',2); hold off %! xlabel('time'); ylabel('V(t)') %! title ('On demand use of sigmoid train') %! axis tight %! #------------------------------------------------------------------------- %! # The colored regions show periods when the force is active. signal-1.4.5/inst/sos2ss.m0000644000000000000000000000233114456505401013556 0ustar0000000000000000## Copyright (C) 2018 John W. Eaton ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} sos2ss (@var{sos}) ## Convert series second-order sections to state-space. ## ## @seealso{sos2ss, ss2tf} ## @end deftypefn function [a, b, c, d] = sos2ss (sos, g = 1) if (nargin < 1 || nargin > 2) print_usage (); endif [num, den] = sos2tf (sos, g); [a, b, c, d] = tf2ss (num, den); endfunction %!test %! sos = [1, 1, 0, 1, 0.5, 0]; %! g = 1; %! [a, b, c, d] = sos2ss (sos, g); %! assert ({a, b, c, d}, {-0.5, 0.5, 1, 1}); signal-1.4.5/inst/sos2tf.m0000644000000000000000000001266714456505401013557 0ustar0000000000000000## Copyright (C) 2005 Julius O. Smith III ## Copyright (C) 2021-2022 Charles Praplan ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{b}, @var{a}] =} sos2tf (@var{sos}) ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} sos2tf (@var{sos}, @var{g}) ## Convert series second-order sections to transfer function. ## ## INPUTS: ## @itemize ## ## @item ## @var{sos} = matrix of series second-order sections, one per row: ## @example ## @var{sos} = [@var{B1}.' @var{A1}.'; ...; @var{BN}.' @var{AN}.'] ## @end example ## where ## @code{@var{B1}.' = [b0 b1 b2] and @var{A1}.' = [a0 a1 a2]} for ## section 1, etc. ## ## a0 is usually equal to 1 because all 2nd order transfer functions ## can be scaled so that a0 = 1. ## However, this is not mandatory for this implementation, which supports ## all kinds of transfer functions, including first order transfer functions. ## See @code{filter} for documentation of the second-order direct-form filter ## coefficients @var{B}i and @var{A}i. ## ## @item ## @var{g} is an overall gain factor that effectively scales ## the output @var{b} vector (or any one of the input @var{B}i vectors). ## If not given the gain is assumed to be 1. ## @end itemize ## ## RETURNED: ## @var{b} and @var{a} are vectors specifying the analog or digital filter ## @math{H(s) = B(s)/A(s)} or @math{H(z) = B(z)/A(z)}. ## See @code{filter} for further details. ## ## @seealso{tf2sos, zp2sos, sos2pz, zp2tf, tf2zp} ## @end deftypefn function [B,A] = sos2tf(sos, g = 1) if (nargin < 1 || nargin > 2) print_usage; endif [N,M] = size(sos); if M~=6 error('sos2tf: sos matrix should be N by 6'); endif A = 1; B = 1; for i=1:N B = conv(B, sos(i,1:3)); A = conv(A, sos(i,4:6)); endfor nA = length (A); nB = length (B); if nA ~= nB error('Internal error: length (A) not equal to length (B)'); # This error cannot occur (if the above calls to the conv function # are not modified and if the conv function is also not modified) endif; clear nA; # Removing trailing zeros if present in numerator and denominator while nB && B(nB)==0 && A(nB)==0 B = B(1:nB-1); A = A(1:nB-1); nB = length (B); endwhile # Removing leading zeros if present in numerator and denominator while nB && B(1)==0 && A(1)==0 A = A(2:end); B = B(2:end); nB--; endwhile B = B .* prod (g); endfunction %!test %! B = [1, 1]; %! A = [1, 0.5]; %! [sos, g] = tf2sos (B, A); %! [Bh, Ah] = sos2tf (sos, g); %! assert (g, 1); %! assert (Bh, B, 10*eps); %! assert (Ah, A, 10*eps); %!test %! B = [1, 0, 0, 0, 0, 1]; %! A = [1, 0, 0, 0, 0, 0.9]; %! [sos, g] = tf2sos (B, A); %! [Bh, Ah] = sos2tf (sos, g); %! assert (g, 1); %! assert (Bh, B, 100*eps); %! assert (Ah, A, 100*eps); ## Test that gain is applied to the B vector %!test %! B = [1, 1]; %! A = [1, 0.5]; %! [sos, g] = tf2sos (B, A); %! [Bh, Ah] = sos2tf (sos, 2); %! assert (g, 1); %! assert (Bh, 2 * B, 10*eps); %! assert (Ah, A, 10*eps); ## Test that a vector of gain is applied as the total product %!test %! B = [1, 1]; %! A = [1, 0.5]; %! [sos, g] = tf2sos (B, A); %! [Bh, Ah] = sos2tf (sos, [2, 2, 2]); %! assert (g, 1); %! assert (Bh, 8 * B, 10*eps); %! assert (Ah, A, 10*eps); ## Test with trailing zero in numerator %!test %! sos = [1, 1, 0, 0, 1, 0.5]; %! [Bh, Ah] = sos2tf (sos); %! assert (Bh, sos(1,1:3) , 10*eps); %! assert (Ah, sos(1,4:6), 10*eps); ## Test with trailing zero in denominator %!test %! sos = [0, 1, 1, 1, 0.5, 0]; %! [Bh, Ah] = sos2tf (sos); %! assert (Bh, sos(1,1:3) , 10*eps); %! assert (Ah, sos(1,4:6), 10*eps); ## Test with trailing zero both in numerator and in denominator %!test %! sos = [1, 1, 0, 1, 0.5, 0]; %! [Bh, Ah] = sos2tf (sos); %! assert (Bh, [1, 1] , 10*eps); %! assert (Ah, [1, 0.5], 10*eps); ## Test with leading zero in numerator %!test %! sos = [0, 1, 1, 1, 1, 0.5]; %! [Bh, Ah] = sos2tf (sos); %! assert (Bh, sos(1,1:3) , 10*eps); %! assert (Ah, sos(1,4:6), 10*eps); ## Test with leading zero in denominator %!test %! sos = [1, 1, 0, 0, 1, 0.5]; %! [Bh, Ah] = sos2tf (sos); %! assert (Bh, sos(1,1:3) , 10*eps); %! assert (Ah, sos(1,4:6), 10*eps); ## Test with leading zero both in numerator and in denominator %!test %! sos = [0, 1, 1, 0, 1, 0.5]; %! [Bh, Ah] = sos2tf (sos); %! assert (Bh, [1, 1] , 10*eps); %! assert (Ah, [1, 0.5], 10*eps); ## Test with 3 trailing zeros both in numerator and in denominator %!test %! sos = [1, 1, 0, 1, 0.5, 0; 1, 1, 0, 1, 0.5, 0; 1, 1, 0, 1, 0.5, 0]; %! [Bh, Ah] = sos2tf (sos); %! assert (Bh, [1, 3, 3, 1] , 10*eps); %! assert (Ah, [1, 1.5 0.75 0.125], 10*eps); ## Test with 3 leading zeros both in numerator and in denominator %!test %! sos = [0, 1, 1, 0, 1, 0.5; 0, 1, 1, 0, 1, 0.5;0, 1, 1, 0, 1, 0.5]; %! [Bh, Ah] = sos2tf (sos); %! assert (Bh, [1, 3, 3, 1] , 10*eps); %! assert (Ah, [1, 1.5 0.75 0.125], 10*eps); signal-1.4.5/inst/sos2zp.m0000644000000000000000000001155014456505401013565 0ustar0000000000000000## Copyright (C) 2005 Julius O. Smith III ## Copyright (C) 2021 Charles Praplan ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{z}, @var{p}, @var{k}] =} sos2zp (@var{sos}) ## @deftypefnx {Function File} {[@var{z}, @var{p}, @var{k}] =} sos2zp (@var{sos}, @var{g}) ## Convert series second-order sections to zeros, poles, and gains ## (pole residues). ## ## INPUTS: ## @itemize ## ## @item ## @var{sos} = matrix of series second-order sections, one per row: ## @example ## @var{sos} = [@var{B1}.' @var{A1}.'; ...; @var{BN}.' @var{AN}.'] ## @end example ## where ## @code{@var{B1}.' = [b0 b1 b2] and @var{A1}.' = [a0 a1 a2]} for ## section 1, etc. ## ## a0 is usually equal to 1 because all 2nd order transfer functions can ## be scaled so that a0 = 1. ## However, this is not mandatory for this implementation, which supports ## all kinds of transfer functions, including first order transfer functions. ## See @code{filter} for documentation of the second-order direct-form filter ## coefficients @var{B}i and @var{A}i. ## ## @item ## @var{g} is an overall gain factor that effectively scales ## any one of the input @var{B}i vectors. ## If not given the gain is assumed to be 1. ## @end itemize ## ## RETURNED: ## @itemize ## @item ## @var{z} = column-vector containing all zeros (roots of B(z)) ## @item ## @var{p} = column-vector containing all poles (roots of A(z)) ## @item ## @var{k} = overall gain = @var{B}(Inf) ## @end itemize ## ## EXAMPLE: ## @example ## [z, p, k] = sos2zp ([1 0 1, 1 0 -0.81; 1 0 0, 1 0 0.49]) ## @result{} z = ## 0 + 1i ## 0 - 1i ## 0 + 0i ## 0 + 0i ## @result{} p = ## -0.9000 + 0i ## 0.9000 + 0i ## 0 + 0.7000i ## 0 - 0.7000i ## @result{} k = 1 ## @end example ## ## @seealso{zp2sos, sos2tf, tf2sos, zp2tf, tf2zp} ## @end deftypefn function [z,p,k] = sos2zp (sos, g = 1) if (nargin < 1 || nargin > 2) print_usage; endif [N,m] = size(sos); if m~=6, error('sos2zp: sos matrix should be N by 6'); endif k = g; for i = 1:N b = sos(i,1:3); N2 = 3; while N2 && b(1)==0 # Removing leading zeros b = b(2:end); N2 = N2 - 1; endwhile a = sos(i,4:6); N2 = 3; while N2 && a(1)==0 # Removing leading zeros a = a(2:end); N2--; endwhile if isempty (a) warning ('Infinite gain detected'); k = Inf; elseif a(1) == 0 warning ('Infinite gain detected'); k = Inf; elseif isempty (b) k = 0; else k = k * b(1) / a(1); endif endfor z = []; p = []; for i=1:N z=[z; roots(sos(i,1:3))]; p=[p; roots(sos(i,4:6))]; endfor endfunction %!test %! b1t=[1 2 3]; a1t=[1 .2 .3]; %! b2t=[4 5 6]; a2t=[1 .4 .5]; %! sos=[b1t a1t; b2t a2t]; %! z = [-1-1.41421356237310i;-1+1.41421356237310i;... %! -0.625-1.05326872164704i;-0.625+1.05326872164704i]; %! p = [-0.2-0.678232998312527i;-0.2+0.678232998312527i;... %! -0.1-0.538516480713450i;-0.1+0.538516480713450i]; %! k = 4; %! [z2,p2,k2] = sos2zp(sos,1); %! assert({cplxpair(z2),cplxpair(p2),k2},{z,p,k},100*eps); ## Test with trailing zero in numerator %!test %! sos = [1, 1, 0, 1, 1, 0.5]; %! [Z, P] = sos2zp (sos); %! assert (Z, roots (sos(1,1:3)), 10*eps); %! assert (P, roots (sos(1,4:6)), 10*eps); ## Test with trailing zero in denominator %!test %! sos = [0, 1, 1, 1, 0.5, 0]; %! [Z, P] = sos2zp (sos); %! assert (Z, roots (sos(1,1:3)), 10*eps); %! assert (P, roots (sos(1,4:6)), 10*eps); ## Test with trailing zero both in numerator and in denominator %!test %! sos = [1, 1, 0, 1, 0.5, 0]; %! [Z, P] = sos2zp (sos); %! assert (Z, roots (sos(1,1:3)), 10*eps); %! assert (P, roots (sos(1,4:6)), 10*eps); ## Test with leading zero in numerator %!test %! sos = [0, 1, 1, 1, 1, 0.5]; %! [Z, P] = sos2zp (sos); %! assert (Z, roots (sos(1,1:3)), 10*eps); %! assert (P, roots (sos(1,4:6)), 10*eps); ## Test with leading zero in denominator %!test %! sos = [1, 1, 0, 0, 1, 0.5]; %! [Z, P] = sos2zp (sos); %! assert (Z, roots (sos(1,1:3)), 10*eps); %! assert (P, roots (sos(1,4:6)), 10*eps); ## Test with leading zero both in numerator and in denominator %!test %! sos = [0, 1, 1, 0, 1, 0.5]; %! [Z, P] = sos2zp (sos); %! assert (Z, roots (sos(1,1:3)), 10*eps); %! assert (P, roots (sos(1,4:6)), 10*eps); signal-1.4.5/inst/specgram.m0000644000000000000000000002231414456505401014126 0ustar0000000000000000## Copyright (C) 1999-2001 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} specgram (@var{x}) ## @deftypefnx {Function File} {} specgram (@var{x}, @var{n}) ## @deftypefnx {Function File} {} specgram (@var{x}, @var{n}, @var{Fs}) ## @deftypefnx {Function File} {} specgram (@var{x}, @var{n}, @var{Fs}, @var{window}) ## @deftypefnx {Function File} {} specgram (@var{x}, @var{n}, @var{Fs}, @var{window}, @var{overlap}) ## @deftypefnx {Function File} {[@var{S}, @var{f}, @var{t}] =} specgram (@dots{}) ## ## Generate a spectrogram for the signal @var{x}. The signal is chopped into ## overlapping segments of length @var{n}, and each segment is windowed and ## transformed into the frequency domain using the FFT. The default segment ## size is 256. If @var{fs} is given, it specifies the sampling rate of the ## input signal. The argument @var{window} specifies an alternate window to ## apply rather than the default of @code{hanning (@var{n})}. The argument ## @var{overlap} specifies the number of samples overlap between successive ## segments of the input signal. The default overlap is ## @code{length (@var{window})/2}. ## ## If no output arguments are given, the spectrogram is displayed. Otherwise, ## @var{S} is the complex output of the FFT, one row per slice, @var{f} is the ## frequency indices corresponding to the rows of @var{S}, and @var{t} is the ## time indices corresponding to the columns of @var{S}. ## ## Example: ## @example ## @group ## x = chirp([0:0.001:2],0,2,500); # freq. sweep from 0-500 over 2 sec. ## Fs=1000; # sampled every 0.001 sec so rate is 1 kHz ## step=ceil(20*Fs/1000); # one spectral slice every 20 ms ## window=ceil(100*Fs/1000); # 100 ms data window ## specgram(x, 2^nextpow2(window), Fs, window, window-step); ## ## ## Speech spectrogram ## [x, Fs] = auload(file_in_loadpath("sample.wav")); # audio file ## step = fix(5*Fs/1000); # one spectral slice every 5 ms ## window = fix(40*Fs/1000); # 40 ms data window ## fftn = 2^nextpow2(window); # next highest power of 2 ## [S, f, t] = specgram(x, fftn, Fs, window, window-step); ## S = abs(S(2:fftn*4000/Fs,:)); # magnitude in range 0= minF & f <= maxF); ## ## Then there is the choice of colormap. A brightness varying colormap ## such as copper or bone gives good shape to the ridges and valleys. A ## hue varying colormap such as jet or hsv gives an indication of the ## steepness of the slopes. The final spectrogram is displayed in log ## energy scale and by convention has low frequencies on the bottom of ## the image: ## ## imagesc(t, f, flipud(log(S(idx,:)))); ## @end deftypefn function [S_r, f_r, t_r] = specgram(x, n = min(256, length(x)), Fs = 2, window = hanning(n), overlap = ceil(length(window)/2)) if (nargin < 1 || nargin > 5) print_usage (); endif if (! isnumeric (x) || ! isvector (x)) error ("specgram: X must be a numeric vector"); endif x = x(:); ## if only the window length is given, generate hanning window if (isscalar (window)) window = hanning (window); endif ## should be extended to accept a vector of frequencies at which to ## evaluate the Fourier transform (via filterbank or chirp ## z-transform) if (! isscalar (n)) error ("specgram: N must be a scalar, vector of frequencies not supported"); endif if (length (x) <= length (window)) error ("specgram: segment length must be less than the size of X"); endif ## compute window offsets win_size = length(window); if (win_size > n) n = win_size; warning ("specgram fft size adjusted to %d", n); endif step = win_size - overlap; ## build matrix of windowed data slices offset = [ 1 : step : length(x)-win_size ]; S = zeros (n, length(offset)); for i=1:length(offset) S(1:win_size, i) = x(offset(i):offset(i)+win_size-1) .* window; endfor ## compute Fourier transform S = fft (S); ## extract the positive frequency components if rem(n,2)==1 ret_n = (n+1)/2; else ret_n = n/2; endif S = S(1:ret_n, :); f = [0:ret_n-1]*Fs/n; t = offset/Fs; if nargout==0 imagesc(t, f, 20*log10(abs(S))); set (gca (), "ydir", "normal"); xlabel ("Time") ylabel ("Frequency") endif if nargout>0, S_r = S; endif if nargout>1, f_r = f; endif if nargout>2, t_r = t; endif endfunction %!shared S,f,t,x %! Fs=1000; %! x = chirp([0:1/Fs:2],0,2,500); # freq. sweep from 0-500 over 2 sec. %! step=ceil(20*Fs/1000); # one spectral slice every 20 ms %! window=ceil(100*Fs/1000); # 100 ms data window %! [S, f, t] = specgram(x); %! ## test of returned shape %!assert (rows(S), 128) %!assert (columns(f), rows(S)) %!assert (columns(t), columns(S)) %!test [S, f, t] = specgram(x'); %!assert (rows(S), 128) %!assert (columns(f), rows(S)); %!assert (columns(t), columns(S)); %!error (isempty(specgram([]))); %!error (isempty(specgram([1, 2 ; 3, 4]))); %!error (specgram) %!demo %! Fs=1000; %! x = chirp([0:1/Fs:2],0,2,500); # freq. sweep from 0-500 over 2 sec. %! step=ceil(20*Fs/1000); # one spectral slice every 20 ms %! window=ceil(100*Fs/1000); # 100 ms data window %! %! ## test of automatic plot %! [S, f, t] = specgram(x); %! specgram(x, 2^nextpow2(window), Fs, window, window-step); %!#demo # FIXME: Enable once we have an audio file to demo %! ## Speech spectrogram %! [x, Fs] = auload(file_in_loadpath("sample.wav")); # audio file %! step = fix(5*Fs/1000); # one spectral slice every 5 ms %! window = fix(40*Fs/1000); # 40 ms data window %! fftn = 2^nextpow2(window); # next highest power of 2 %! [S, f, t] = specgram(x, fftn, Fs, window, window-step); %! S = abs(S(2:fftn*4000/Fs,:)); # magnitude in range 0 (2006) ## This program is granted to the public domain. ## -*- texinfo -*- ## @deftypefn {Function File} {@var{s} =} square (@var{t}, @var{duty}) ## @deftypefnx {Function File} {@var{s} =} square (@var{t}) ## Generate a square wave of period 2 pi with limits +1/-1. ## ## If @var{duty} is specified, it is the percentage of time the square ## wave is "on". The square wave is +1 for that portion of the time. ## ## @verbatim ## on time * 100 ## duty cycle = ------------------ ## on time + off time ## @end verbatim ## ## @seealso{cos, sawtooth, sin, tripuls} ## @end deftypefn function v = square (t, duty = 50) if (nargin < 1 || nargin > 2) print_usage; endif duty /= 100; t /= 2*pi; v = ones(size(t)); v(t-floor(t) >= duty) = -1; endfunction signal-1.4.5/inst/ss2tf.m0000644000000000000000000000334214456505401013366 0ustar0000000000000000## Copyright (C) 1994, 1996, 2000, 2004, 2005, 2007 Auburn University ## Copyright (C) 2012 Lukas F. Reichlin ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{num}, @var{den}] =} ss2tf (@var{a}, @var{b}, @var{c}, @var{d}) ## Conversion from state-space to transfer function representation. ## The state space system: ## @tex ## $$ \dot x = Ax + Bu $$ ## $$ y = Cx + Du $$ ## @end tex ## @ifnottex ## @example ## @group ## . ## x = Ax + Bu ## y = Cx + Du ## @end group ## @end example ## @end ifnottex ## ## is converted to a transfer function: ## @tex ## $$ G(s) = { { \rm num }(s) \over { \rm den }(s) } $$ ## @end tex ## @ifnottex ## @example ## @group ## num(s) ## G(s)=------- ## den(s) ## @end group ## @end example ## @end ifnottex ## ## @end deftypefn ## Author: R. Bruce Tenison function [num, den] = ss2tf (varargin) if (nargin == 0) print_usage (); endif [num, den] = tfdata (ss (varargin{:}), "vector"); endfunction signal-1.4.5/inst/ss2zp.m0000644000000000000000000000235014456505401013404 0ustar0000000000000000## Copyright (C) 1994, 1996, 2000, 2004, 2005, 2006, 2007 Auburn University ## Copyright (C) 2012 Lukas F. Reichlin ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{z}, @var{p}, @var{k}] =} ss2zp (@var{a}, @var{b}, @var{c}, @var{d}) ## Converts a state space representation to a set of poles and zeros; ## @var{k} is a gain associated with the zeros. ## ## @end deftypefn ## Author: David Clem function [z, p, k] = ss2zp (varargin) if (nargin == 0) print_usage (); endif [z, p, k] = zpkdata (ss (varargin{:}), "vector"); endfunction signal-1.4.5/inst/statelevels.m0000644000000000000000000001722614456505401014666 0ustar0000000000000000## Copyright (C) 2016 Chris Adams ## ## This program is free software; you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{levels} =} statelevels (@var{A}) ## @deftypefnx {Function File} {@var{levels} =} statelevels (@var{A}, @var{nbins}) ## @deftypefnx {Function File} {@var{levels} =} statelevels (@var{A}, @var{nbins}, @var{method}) ## @deftypefnx {Function File} {@var{levels} =} statelevels (@var{A}, @var{nbins}, @var{method}, @var{bounds}) ## @deftypefnx {Function File} {[@var{levels}, @var{histograms}] =} statelevels (@dots{}) ## @deftypefnx {Function File} {[@var{levels}, @var{histograms}, @var{binlevels}] =} statelevels (@dots{}) ## @deftypefnx {Function File} {} statelevels (@dots{}) ## Estimate state-level for bilevel waveform @var{A} using histogram method ## ## INPUTS: ## ## @table @var ## @item A ## Bylevel waveform ## @item nbins ## Number of histogram bins (100 default) ## @item method ## State-level estimation method 'mode' (default) or 'mean'. ## @item bounds ## 2 element vector for histogram lower and upper bounds. Values outside of this will be ignored. ## @end table ## ## OUTPUTS: ## ## @table @var ## @item levels ## Levels of high and low states ## @item histograms ## Histogram counts ## @item binlevels ## Histogram bincenters ## @end table ## ## If no outputs are provided, the signal and histogram will be plotted, and display the levels. ## ## @end deftypefn function varargout = statelevels (A, varargin) if nargin == 0 || nargin > 4 || nargout > 3 print_usage() endif # Setup arguments based on number of given arguments nBins = 100; method = 1; if nargin > 1 if !isnumeric (varargin{1}) error ('statelevels expects a number for argument 2'); endif nBins = varargin{1}; endif if nargin > 2 if !ischar(varargin{2}) error ("Expected method of 'mode' or 'mean'") endif if strcmp(varargin{2}, 'mode') method = 1; elseif strcmp(varargin{2}, 'mean') method = 0; else error ("Expected method of 'mode' or 'mean'") endif endif # Get size first for various uses sz = size(A); # Row column vector checking # Are any of the columns of size one? if (sz(1) != 1 && sz(2) != 1) || (sz(1) == 1 && sz(2) == 1) error ('statelevels expects a numeric vector for waveform'); endif if !isnumeric(A) || !isreal(A) error ('statelevels expects a numeric vector for waveform'); endif # Switch to row if it's a column vector if sz(2) == 1 X = A'; else X = A; endif if nargin > 3 b = varargin{3}; if !isnumeric(b) || !isreal(b) || length(b) != 2 error ('statelevels expects a 2 element numeric vector for bounds'); endif lower = b(1); upper = b(2); if upper < lower error ('Upper bound should be greater than lower bound'); endif else upper = max(X)+eps; lower = min(X)-eps; endif # Generate hist vector based on the bounds in the histogram histVec = lower + ((1:nBins) - 0.5)' * (upper - lower) / nBins; # Get a histogram # Generate indexes for the histogram idx = ceil(nBins * (X-lower)/(upper-lower)); # Pick only indexes in the range idx = idx(idx>=1 & idx<=nBins); # Initialise the histogram with zeros histogram = zeros(nBins, 1); # For every valid index increment the value if it hits for i = 1:size (idx,2) histogram(idx(i)) = histogram(idx(i)) + 1; endfor # Find the bounds, lowest non zero and highest iLow = 0; iHigh = 0; for i = 1:nBins if histogram(i) > 0 iLow = i; break; endif endfor for i = nBins:-1:1 if histogram(i) > 0 iHigh = i; break; endif endfor # Define index pairs that define the lower and upper histogram slices. # We'll need these later lLow = iLow; lHigh = iLow + floor ((iHigh - iLow)/2); uLow = iLow + floor ((iHigh - iLow)/2); uHigh = iHigh; lHist = histogram(iLow:lHigh, 1); uHist = histogram(uLow:uHigh, 1); # What's the amplitude, size ratio (see ref) dy = (upper-lower) / size (histogram,1); # If mode (default) if method == 1 [~, iMax] = max (lHist); [~, iMin] = max (uHist); S1 = lower + dy * (lLow + iMax(1) - 1.5); S2 = lower + dy * (uLow + iMin(1) - 1.5); elseif (method==0) S1 = lower + dy * dot ((lLow:lHigh)-0.5, lHist) / sum (lHist); S2 = lower + dy * dot ((uLow:uHigh)-0.5, uHist) / sum (uHist); endif varargout{1} = [S1 S2]; if nargout == 0 f = figure(); subplot (2, 1, 1); plot(A) title('Signal'); xlabel('Samples'); ylabel('Level'); subplot (2, 1, 2); plot(histVec, histogram); title(sprintf('Histogram of signal levels (%d bins)', nBins)); xlabel('Level'); ylabel('Count'); endif if nargout > 1 varargout{2} = histogram; endif if nargout > 2 varargout{3} = histVec; endif endfunction %! ## test input validation %!error l = statelevels() %!error l = statelevels("test") %!error l = statelevels(1) %!error l = statelevels([1 2 3], 'test') %!error l = statelevels([1 2 3], 3, 'test') %!error l = statelevels([1 2 3], 3, 'mode', 1) %!error l = statelevels([1 2 3], 3, 'mode', [1 -1]) %!shared X %! t = linspace(0,2*pi*10,100); %! X = square(t) + cos(t); %!test %! l = statelevels(X); %! assert(l, [-1.9795 1.9800], 1e5) %!test %! [l, h] = statelevels(X); %! assert(l, [-1.9795 1.9800], 1e5) %! assert(sum(h), 100) %! assert(length(h), 100) %!test %! [l, h, b] = statelevels(X); %! assert(l, [-1.9795 1.9800], 1e5) %! assert(sum(h), 100) %! assert(length(h), 100) %! assert(h(1), 4) %! assert(h(2), 2) %! assert(h(4), 1) %! assert(h(11), 0) %! assert(b(1), -1.9795, 1e5) %! assert(b(2), -1.9395, 1e5) %!test %! [l, h, b] = statelevels(X, 100); %! assert(l, [-1.9795 1.9800], 1e5) %! assert(sum(h), 100) %! assert(length(h), 100) %! assert(h(1), 4) %! assert(h(2), 2) %! assert(h(4), 1) %! assert(h(11), 0) %! assert(b(1), -1.9795, 1e5) %! assert(b(2), -1.9395, 1e5) %!test %! [l, h, b] = statelevels(X, 50); %! assert(l, [-1.9595 1.9600], 1e5) %! assert(sum(h), 100) %! assert(length(h), 50) %! assert(h(1), 6) %! assert(h(2), 3) %! assert(h(4), 2) %! assert(h(11), 1) %! assert(b(1), -1.9595, 1e5) %! assert(b(2), -1.8795, 1e5) %!test %! [l, h, b] = statelevels(X, 100, 'mode'); %! assert(l, [-1.9795 1.9800], 1e5) %! assert(sum(h), 100) %! assert(length(h), 100) %! assert(h(1), 4) %! assert(h(2), 2) %! assert(h(4), 1) %! assert(h(11), 0) %! assert(b(1), -1.9795, 1e5) %! assert(b(2), -1.9395, 1e5) %!test %! [l, h, b] = statelevels(X, 100, 'mean'); %! assert(l, [-1.0090 0.9532], 1e5) %! assert(sum(h), 100) %! assert(length(h), 100) %! assert(h(1), 4) %! assert(h(2), 2) %! assert(h(4), 1) %! assert(h(11), 0) %! assert(b(1), -1.9795, 1e5) %! assert(b(2), -1.9395, 1e5) %!test %! [l, h, b] = statelevels(X, 100, 'mode', [-1.8 1.0]); %! assert(l, [-1.7860 0.0060], 1e5) %! assert(sum(h), 64) %! assert(length(h), 100) %! assert(h(1), 1) %! assert(h(2), 1) %! assert(h(3), 0) %! assert(b(1), -1.7860, 1e5) %! assert(b(2), -1.7580, 1e5) %!demo %! # Generate test signal %! t = linspace(0,2*pi*10,100); %! X = square(t) + cos(t); %! # plot the waveform and provide the levels %! statelevels(X) signal-1.4.5/inst/tf2sos.m0000644000000000000000000000475314456505401013554 0ustar0000000000000000## Copyright (C) 2005 Julius O. Smith III ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{sos}, @var{g}] =} tf2sos (@var{b}, @var{a}) ## @deftypefnx {Function File} {@var{sos} =} tf2sos (@var{b}, @var{a}) ## Convert direct-form filter coefficients to series second-order sections. ## ## INPUTS: ## ## @var{b} and @var{a} are vectors specifying the digital filter ## @math{H(z) = B(z)/A(z)}. See @code{filter} for documentation of the @var{b} ## and @var{a} filter coefficients. ## ## RETURNED: ## @itemize ## @item ## @var{sos} = matrix of series second-order sections, one per row: ## @example ## @var{sos} = [@var{b1}.' @var{a1}.'; ...; @var{bn}.' @var{an}.'] ## @end example ## where ## @code{@var{B1}.' = [b0 b1 b2] and @var{A1}.' = [1 a1 a2]} for ## section 1, etc. The b0 entry must be nonzero for each section (zeros at ## infinity not supported). ## @item ## @var{g} is an overall gain factor that effectively scales ## any one of the @var{B}i vectors. ## @end itemize ## ## If called with only one output argument, the overall filter gain is ## applied to the first second-order section in the matrix @var{sos}. ## ## EXAMPLE: ## @example ## B = [1 0 0 0 0 1]; ## A = [1 0 0 0 0 .9]; ## [sos, g] = tf2sos (B, A) ## ## sos = ## ## 1.00000 0.61803 1.00000 1.00000 0.60515 0.95873 ## 1.00000 -1.61803 1.00000 1.00000 -1.58430 0.95873 ## 1.00000 1.00000 -0.00000 1.00000 0.97915 -0.00000 ## ## g = 1 ## @end example ## ## @seealso{sos2tf, zp2sos, sos2pz, zp2tf, tf2zp} ## @end deftypefn function [sos,g] = tf2sos (B, A) [z,p,k] = tf2zp(B(:)',A(:)'); if (nargout < 2) sos = zp2sos(z,p,k); else [sos,g] = zp2sos(z,p,k); endif endfunction %!test %! B=[1 0 0 0 0 1]; A=[1 0 0 0 0 .9]; %! [sos,g] = tf2sos(B,A); %! [Bh,Ah] = sos2tf(sos,g); %! assert({Bh,Ah},{B,A},100*eps); signal-1.4.5/inst/tf2ss.m0000644000000000000000000000354514456505401013373 0ustar0000000000000000## Copyright (C) 1994-1996, 1998, 2000, 2002, 2004, 2005, 2007 Auburn University ## Copyright (C) 2012 Lukas F. Reichlin ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} tf2ss (@var{num}, @var{den}) ## Conversion from transfer function to state-space. ## The state space system: ## @tex ## $$ \dot x = Ax + Bu $$ ## $$ y = Cx + Du $$ ## @end tex ## @ifnottex ## @example ## @group ## . ## x = Ax + Bu ## y = Cx + Du ## @end group ## @end example ## @end ifnottex ## is obtained from a transfer function: ## @tex ## $$ G(s) = { { \rm num }(s) \over { \rm den }(s) } $$ ## @end tex ## @ifnottex ## @example ## @group ## num(s) ## G(s)=------- ## den(s) ## @end group ## @end example ## @end ifnottex ## ## The state space system matrices obtained from this function ## will be in observable companion form as Wolovich's Observable ## Structure Theorem is used. ## @end deftypefn ## Author: R. Bruce Tenison function [a, b, c, d, e] = tf2ss (varargin) if (nargin == 0) print_usage (); endif [a, b, c, d, e] = dssdata (tf (varargin{:}), []); endfunction signal-1.4.5/inst/tf2zp.m0000644000000000000000000000251614456505401013374 0ustar0000000000000000## Copyright (C) 1996, 1998, 2000, 2003, 2004, 2005, 2006, 2007 Auburn University ## Copyright (C) 2012 Lukas F. Reichlin ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{z}, @var{p}, @var{k}] =} tf2zp (@var{num}, @var{den}) ## Convert transfer functions to poles-and-zero representations. ## ## Returns the zeros and poles of the system defined ## by @var{num}/@var{den}. ## @var{k} is a gain associated with the system zeros. ## @end deftypefn ## Author: A. S. Hodel function [z, p, k] = tf2zp (varargin) if (nargin == 0) print_usage (); endif [z, p, k] = zpkdata (tf (varargin{:}), "vector"); endfunction signal-1.4.5/inst/tfe.m0000644000000000000000000000400314456505401013076 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[Pxx,freq] =} tfe(x,y,Nfft,Fs,window,overlap,range,plot_type,detrend) ## Estimate transfer function of system with input "x" and output "y". ## ## Use the Welch (1967) periodogram/FFT method. ## ## Compatible with Matlab R11 tfe and earlier. ## ## See "help pwelch" for description of arguments, hints and references ## --- especially hint (7) for Matlab R11 defaults. ## @end deftypefn function varargout = tfe(varargin) ## ## Check fixed argument if ( nargin<2 ) error( 'tfe: Need at least 2 args. Use help tfe.' ); endif nvarargin = length(varargin); ## remove any pwelch RESULT args and add 'trans' for iarg=1:nvarargin arg = varargin{iarg}; if ( ~isempty(arg) && ischar(arg) && ( strcmp(arg,'power') || ... strcmp(arg,'cross') || strcmp(arg,'trans') || ... strcmp(arg,'coher') || strcmp(arg,'ypower') )) varargin{iarg} = []; endif endfor varargin{nvarargin+1} = 'trans'; ## saved_compatib = pwelch('R11-'); if ( nargout==0 ) pwelch(varargin{:}); elseif ( nargout==1 ) Pxx = pwelch(varargin{:}); varargout{1} = Pxx; elseif ( nargout>=2 ) [Pxx,f] = pwelch(varargin{:}); varargout{1} = Pxx; varargout{2} = f; endif pwelch(saved_compatib); endfunction signal-1.4.5/inst/tfestimate.m0000644000000000000000000000452314456505401014474 0ustar0000000000000000## Copyright (C) 2006 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} tfestimate (@var{x}, @var{y}) ## @deftypefnx {Function File} {} tfestimate (@var{x}, @var{y}, @var{window}) ## @deftypefnx {Function File} {} tfestimate (@var{x}, @var{y}, @var{window}, @var{overlap}) ## @deftypefnx {Function File} {} tfestimate (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}) ## @deftypefnx {Function File} {} tfestimate (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}) ## @deftypefnx {Function File} {} tfestimate (@var{x}, @var{y}, @var{window}, @var{overlap}, @var{Nfft}, @var{Fs}, @var{range}) ## @deftypefnx {Function File} {[@var{Pxx}, @var{freq}] =} tfestimate (@dots{}) ## ## Estimate transfer function of system with input @var{x} and output @var{y}. ## Use the Welch (1967) periodogram/FFT method. ## @seealso{pwelch} ## @end deftypefn function varargout = tfestimate(varargin) ## ## Check fixed argument if (nargin < 2 || nargin > 7) print_usage (); endif nvarargin = length(varargin); ## remove any pwelch RESULT args and add 'cross' for iarg=1:nvarargin arg = varargin{iarg}; if ( ~isempty(arg) && ischar(arg) && ( strcmp(arg,'power') || ... strcmp(arg,'cross') || strcmp(arg,'trans') || ... strcmp(arg,'coher') || strcmp(arg,'ypower') )) varargin{iarg} = []; endif endfor varargin{nvarargin+1} = 'trans'; ## if ( nargout==0 ) pwelch(varargin{:}); elseif ( nargout==1 ) Pxx = pwelch(varargin{:}); varargout{1} = Pxx; elseif ( nargout>=2 ) [Pxx,f] = pwelch(varargin{:}); varargout{1} = Pxx; varargout{2} = f; endif endfunction signal-1.4.5/inst/triang.m0000644000000000000000000000472314456505401013615 0ustar0000000000000000## Copyright (C) 2000-2002 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} triang (@var{m}) ## ## Return the filter coefficients of a triangular window of length @var{m}. ## Unlike the Bartlett window, @code{triang} does not go to zero at the edges ## of the window. For odd @var{m}, @code{triang (@var{m})} is equal to ## @code{bartlett (@var{m} + 2)} except for the zeros at the edges of the ## window. ## @seealso{bartlett} ## @end deftypefn function w = triang (m) if (nargin != 1) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("triang: M must be a positive integer"); endif w = 1 - abs ([-(m-1):2:(m-1)]' / (m+rem(m,2))); endfunction %!assert (triang (1), 1) %!assert (triang (2), [1; 1]/2) %!assert (triang (3), [1; 2; 1]/2) %!assert (triang (4), [1; 3; 3; 1]/4) %!test %! x = bartlett (5); %! assert (triang (3), x(2:4)); %% Test input validation %!error triang () %!error triang (0.5) %!error triang (-1) %!error triang (ones (1, 4)) %!error triang (1, 2) %!demo %! subplot(221); %! n=7; k=(n-1)/2; t=[-k:0.1:k]/(k+1); %! plot(t,1-abs(t),";continuous;",[-k:k]/(k+1),triang(n),"g*;discrete;"); %! axis([-1, 1, 0, 1.3]); grid("on"); %! title("comparison with continuous for odd n"); %! %! subplot(222); %! n=8; k=(n-1)/2; t=[-k:0.1:k]/(k+1/2); %! plot(t,1+1/n-abs(t),";continuous;",[-k:k]/(k+1/2),triang(n),"g*;discrete;"); %! axis([-1, 1, 0, 1.3]); grid("on"); %! title("note the higher peak for even n"); %! %! subplot(223); %! n=7; %! plot(0:n+1,bartlett(n+2),"g-*;bartlett;",triang(n),"r-+;triang;"); %! axis; grid("off"); %! title("n odd, triang(n)==bartlett(n+2)"); %! %! subplot(224); %! n=8; %! plot(0:n+1,bartlett(n+2),"g-*;bartlett;",triang(n),"r-+;triang;"); %! axis; grid("off"); %! title("n even, triang(n)!=bartlett(n+2)"); signal-1.4.5/inst/tripuls.m0000644000000000000000000000677014456505401014037 0ustar0000000000000000## Copyright (C) 2001 Paul Kienzle ## Copyright (C) 2018-2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} tripuls (@var{t}) ## @deftypefnx {Function File} {@var{y} =} tripuls (@var{t}, @var{w}) ## @deftypefnx {Function File} {@var{y} =} tripuls (@var{t}, @var{w}, @var{skew}) ## Generate a triangular pulse over the interval [-@var{w}/2,@var{w}/2), ## sampled at times @var{t}. This is useful with the function @code{pulstran} ## for generating a series of pulses. ## ## @var{skew} is a value between -1 and 1, indicating the relative placement ## of the peak within the width. -1 indicates that the peak should be ## at -@var{w}/2, and 1 indicates that the peak should be at @var{w}/2. The ## default value is 0. ## ## Example: ## @example ## @group ## fs = 11025; # arbitrary sample rate ## f0 = 100; # pulse train sample rate ## w = 0.3/f0; # pulse width 3/10th the distance between pulses ## plot (pulstran (0:1/fs:4/f0, 0:1/f0:4/f0, "tripuls", w)); ## @end group ## @end example ## ## @seealso{gauspuls, pulstran, rectpuls} ## @end deftypefn function y = tripuls (t, w = 1, skew = 0) if (nargin < 1 || nargin > 3) print_usage (); endif if (! isreal (w) || ! isscalar (w)) error ("tripuls: W must be a real scalar"); endif if (! isreal (skew) || ! isscalar (skew) || skew < -1 || skew > 1) error ("tripuls: SKEW must be a real scalar in the range [-1, 1]"); endif y = zeros (size (t)); peak = skew * w/2; idx = find ((t >= -w/2) & (t <= peak)); if (idx) y(idx) = (t(idx) + w/2) / (peak + w/2); endif idx = find ((t > peak) & (t < w/2)); if (idx) y(idx) = (t(idx) - w/2) / (peak - w/2); endif endfunction %!demo %! fs = 11025; # arbitrary sample rate %! f0 = 100; # pulse train sample rate %! w = 0.5/f0; # pulse width 1/10th the distance between pulses %! x = pulstran (0:1/fs:4/f0, 0:1/f0:4/f0, "tripuls", w); %! plot ([0:length(x)-1]*1000/fs, x); %! xlabel ("Time (ms)"); %! ylabel ("Amplitude"); %! title ("Triangular pulse train of 5 ms pulses at 10 ms intervals"); %!demo %! fs = 11025; # arbitrary sample rate %! f0 = 100; # pulse train sample rate %! w = 0.5/f0; # pulse width 1/10th the distance between pulses %! x = pulstran (0:1/fs:4/f0, 0:1/f0:4/f0, "tripuls", w, -0.5); %! plot ([0:length(x)-1]*1000/fs, x); %! xlabel ("Time (ms)"); %! ylabel ("Amplitude"); %! title ("Triangular pulse train of 5 ms pulses at 10 ms intervals, skew = -0.5"); %!assert (tripuls ([]), []) %!assert (tripuls ([], 0.1), []) %!assert (tripuls (zeros (10, 1)), ones (10, 1)) %!assert (tripuls (-1:1), [0, 1, 0]) %!assert (tripuls (-5:5, 9), [0, 1, 3, 5, 7, 9, 7, 5, 3, 1, 0] / 9) %!assert (tripuls (0:1/100:0.3, 0.1), tripuls ([0:1/100:0.3]', 0.1)') ## Test input validation %!error tripuls () %!error tripuls (1, 2, 3, 4) %!error tripuls (1, 2j) %!error tripuls (1, 2, 2) %!error tripuls (1, 2, -2) signal-1.4.5/inst/tukeywin.m0000644000000000000000000000522414456505401014205 0ustar0000000000000000## Copyright (C) 2007 Laurent Mazet ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} tukeywin (@var{m}) ## @deftypefnx {Function File} {} tukeywin (@var{m}, @var{r}) ## Return the filter coefficients of a Tukey window (also known as the ## cosine-tapered window) of length @var{m}. @var{r} defines the ratio ## between the constant section and and the cosine section. It has to be ## between 0 and 1. The function returns a Hanning window for @var{r} ## equal to 1 and a rectangular window for @var{r} equal to 0. ## The default value of @var{r} is 1/2. ## ## For a definition of the Tukey window, see e.g. Fredric J. Harris, ## "On the Use of Windows for Harmonic Analysis with the Discrete Fourier ## Transform, Proceedings of the IEEE", Vol. 66, No. 1, January 1978, ## Page 67, Equation 38. ## @seealso{hanning} ## @end deftypefn function w = tukeywin (m, r = 1/2) if (nargin < 1 || nargin > 2) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("tukeywin: M must be a positive integer"); elseif (nargin == 2) ## check that 0 < r < 1 if r > 1 r = 1; elseif r < 0 r = 0; endif endif ## generate window switch r case 0, ## full box w = ones (m, 1); case 1, ## Hanning window w = hanning (m); otherwise ## cosine-tapered window t = linspace(0,1,m)(1:end/2)'; w = (1 + cos(pi*(2*t/r-1)))/2; w(floor(r*(m-1)/2)+2:end) = 1; w = [w; ones(mod(m,2)); flipud(w)]; endswitch endfunction %!demo %! m = 100; %! r = 1/3; %! w = tukeywin (m, r); %! title(sprintf("%d-point Tukey window, R = %d/%d", m, [p, q] = rat(r), q)); %! plot(w); %!assert (tukeywin (1), 1) %!assert (tukeywin (2), zeros (2, 1)) %!assert (tukeywin (3), [0; 1; 0]) %!assert (tukeywin (16, 0), rectwin (16)) %!assert (tukeywin (16, 1), hanning (16)) %% Test input validation %!error tukeywin () %!error tukeywin (0.5) %!error tukeywin (-1) %!error tukeywin (ones (1, 4)) %!error tukeywin (1, 2, 3) signal-1.4.5/inst/udecode.m0000644000000000000000000000714114456505401013736 0ustar0000000000000000## Copyright (C) 2014 Georgios Ouzounis ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{out} =} udecode (@var{in}, @var{n}) ## @deftypefnx {Function File} {@var{out} =} udecode (@var{in}, @var{n}, @var{v}) ## @deftypefnx {Function File} {@var{out} =} udecode (@var{in}, @var{n}, @var{v}, @var{overflows}) ## Invert the operation of uencode. ## @seealso{uencode} ## @end deftypefn function out = udecode (in, n, v = 1, overflows = "saturate") if (nargin < 2 || nargin > 4) print_usage (); endif if (in != fix (in)) error ("udecode: IN must be matrix of integers"); endif if (n < 2 || n > 32 || n != fix (n)) error ("udecode: N must be an integer in the range [2, 32]"); endif if (v <= 0) error ("udecode: V must be a positive integer"); endif if (! (strcmp (overflows, "saturate") || strcmp (overflows, "wrap"))) error ("uencode: OVERFLOWS must be either \"saturate\" or \"wrap\""); endif if ( all (in >= 0)) signed = "unsigned"; lowerlevel = 0; upperlevel = (2 ^ n) - 1; else signed = "signed"; lowerlevel = - 2 ^ (n - 1); upperlevel = (2 ^ (n - 1)) - 1; endif if (strcmp (overflows, "saturate")) if (strcmp (signed, "unsigned")) in(in > upperlevel) = upperlevel; elseif (strcmp (signed, "signed")) in(in < lowerlevel) = lowerlevel; in(in > upperlevel) = upperlevel; endif elseif (strcmp (overflows, "wrap")) if (strcmp (signed, "unsigned")) idx = in > upperlevel; in(idx) = mod (in(idx), 2 ^ n); elseif (strcmp (signed, "signed")) idx = in < lowerlevel; in(idx) = mod (in(idx) + 2 ^ (n - 1), 2 ^ n) - 2 ^ (n - 1); idx = in > upperlevel; in(idx) = mod (in(idx) + 2 ^ (n - 1), 2 ^ n) - 2 ^ (n - 1); endif endif width = 2 * v / 2 ^ n; out = double (in) .* width; if (strcmp (signed, "unsigned")) out = out - v; endif endfunction %!test %! u = [0 0 0 0 0 1 2 3 3 3 3 3 3]; %! y = udecode(u, 2); %! assert(y, [-1 -1 -1 -1 -1 -0.5 0 0.5 0.5 0.5 0.5 0.5 0.5]); %!test %! u = [0 1 2 3 4 5 6 7 8 9 10]; %! y = udecode(u, 2, 1, "saturate"); %! assert(y, [-1 -0.5 0 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5]); %!test %! u = [0 1 2 3 4 5 6 7 8 9 10]; %! y = udecode(u, 2, 1, "wrap"); %! assert(y, [-1 -0.5 0 0.5 -1 -0.5 0 0.5 -1 -0.5 0]); %!test %! u = [-4 -3 -2 -1 0 1 2 3]; %! y = udecode(u, 3, 2); %! assert(y, [-2, -1.5 -1 -0.5 0 0.5 1 1.5]); %!test %! u = [-7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7]; %! y = udecode(u, 3, 2, "saturate"); %! assert(y, [-2 -2 -2 -2 -1.5 -1 -0.5 0 0.5 1 1.5 1.5 1.5 1.5 1.5]); %!test %! u = [-7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7]; %! y = udecode(u, 3, 2, "wrap"); %! assert(y, [0.5 1 1.5 -2 -1.5 -1 -0.5 0 0.5 1 1.5 -2 -1.5 -1 -0.5]); ## Test input validation %!error udecode () %!error udecode (1) %!error udecode (1, 2, 3, 4, 5) %!error udecode (1.5) %!error udecode (1, 100) %!error udecode (1, 4, 0) %!error udecode (1, 4, -1) %!error udecode (1, 4, 2, "invalid") signal-1.4.5/inst/uencode.m0000644000000000000000000000502014456505401013742 0ustar0000000000000000## Copyright (C) 2014 Georgios Ouzounis ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{out} =} uencode (@var{in}, @var{n}) ## @deftypefnx {Function File} {@var{out} =} uencode (@var{in}, @var{n}, @var{v}) ## @deftypefnx {Function File} {@var{out} =} uencode (@var{in}, @var{n}, @var{v}, @var{signed}) ## Quantize the entries of the array @var{in} using 2^@var{n} quantization levels. ## @seealso{udecode} ## @end deftypefn function out = uencode (in, n, v = 1, signed = "unsigned") if (nargin < 2 || nargin > 4) print_usage (); endif if (n < 2 || n > 32 || n != fix (n)) error ("uencode: N must be an integer in the range [2, 32]"); endif if (v <= 0) error ("uencode: V must be a positive integer"); endif if (! (strcmp (signed, "signed") || strcmp (signed, "unsigned"))) error ("uencode: SIGNED must be either \"signed\" or \"unsigned\""); endif out = zeros (size (in)); width = 2 * v / 2 ^ n; out(in >= v) = (2 ^ n) - 1; idx = (in > -v) & (in < v); out(idx) = floor ((in(idx) + v) ./ width); if (strcmp (signed, "signed")) out = out - 2 ^ (n - 1); endif endfunction %!test %! u = [-3:0.5:3]; %! y = uencode (u, 2); %! assert (y, [0 0 0 0 0 1 2 3 3 3 3 3 3]); %!test %! u = [-4:0.5:4]; %! y = uencode (u, 3, 4); %! assert (y, [0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 7]); %!test %! u = [-8:0.5:8]; %! y = uencode(u, 4, 8, "unsigned"); %! assert (y, [0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 15]); %!test %! u = [-8:0.5:8]; %! y = uencode(u, 4, 8, "signed"); %! assert (y, [-8 -8 -7 -7 -6 -6 -5 -5 -4 -4 -3 -3 -2 -2 -1 -1 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 7]); ## Test input validation %!error uencode () %!error uencode (1) %!error uencode (1, 2, 3, 4, 5) %!error uencode (1, 100) %!error uencode (1, 4, 0) %!error uencode (1, 4, -1) %!error uencode (1, 4, 2, "invalid") signal-1.4.5/inst/ultrwin.m0000644000000000000000000002025714456505401014035 0ustar0000000000000000## Copyright (C) 2013 Rob Sykes ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{w}, @var{xmu}] =} ultrwin (@var{m}, @var{mu}, @var{beta}) ## @deftypefnx {Function File} {[@var{w}, @var{xmu}] =} ultrwin (@var{m}, @var{mu}, @var{att}, "att") ## @deftypefnx {Function File} {[@var{w}, @var{xmu}] =} ultrwin (@var{m}, @var{mu}, @var{latt}, "latt") ## @deftypefnx {Function File} {@var{w} =} ultrwin (@var{m}, @var{mu}, @var{xmu}, "xmu") ## Return the coefficients of an Ultraspherical window of length @var{m}. ## The parameter @var{mu} controls the window's Fourier transform's side-lobe ## to side-lobe ratio, and the third given parameter controls the transform's ## main-lobe width/side-lobe-ratio; normalize @var{w} such that the central ## coefficient(s) value is unitary. ## ## By default, the third parameter is @var{beta}, which sets the main lobe width ## to @var{beta} times that of a rectangular window. Alternatively, giving ## @var{att} or @var{latt} sets the ripple ratio at the first or last side-lobe ## respectively, or giving @var{xmu} sets the (un-normalized) window's Fourier ## transform according to its canonical definition: ## ## @verbatim ## (MU) ## W(k) = C [ XMU cos(pi k/M) ], k = 0, 1, ..., M-1, ## M-1 ## @end verbatim ## ## where C is the Ultraspherical (a.k.a. Gegenbauer) polynomial, which can be ## defined using the recurrence relationship: ## ## @verbatim ## (l) 1 (l) (l) ## C (x) = - [ 2x(m + l - 1) C (x) - (m + 2l - 2) C (x) ] ## m m m-1 m-2 ## ## (l) (l) ## for m an integer > 1, and C (x) = 1, C (x) = 2lx. ## 0 1 ## @end verbatim ## ## For given @var{beta}, @var{att}, or @var{latt}, the corresponding ## (determined) value of @var{xmu} is also returned. ## ## The Dolph-Chebyshev and Saramaki windows are special cases of the ## Ultraspherical window, with @var{mu} set to 0 and 1 respectively. Note that ## when not giving @var{xmu}, stability issues may occur with @var{mu} <= -1.5. ## For further information about the window, see ## ## @itemize @bullet ## @item ## Kabal, P., 2009: Time Windows for Linear Prediction of Speech. ## Technical Report, Dept. Elec. & Comp. Eng., McGill University. ## @item ## Bergen, S., Antoniou, A., 2004: Design of Ultraspherical Window ## Functions with Prescribed Spectral Characteristics. Proc. JASP, 13/13, ## pp. 2053-2065. ## @item ## Streit, R., 1984: A two-parameter family of weights for nonrecursive ## digital filters and antennas. Trans. ASSP, 32, pp. 108-118. ## @end itemize ## @seealso{chebwin, kaiser} ## @end deftypefn function [w, xmu] = ultrwin (m, mu, par, key = "beta", norm = 0) ## This list of parameter types must be kept in sync with the enum order. types = {"xmu", "beta", "att", "latt"}; type = []; if (ischar (key)) type = find (strncmpi (key, types, numel (key))); endif if (nargin < 3 || nargin > 5) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("ultrwin: M must be a positive integer"); elseif (! (isscalar (mu) && isreal (mu))) error ("ultrwin: MU must be a real scalar"); elseif (! ischar (key)) error ("ultrwin: parameter type must be a string"); elseif (isempty (type)) error ("ultrwin: invalid parameter type '%s'", key); elseif (! (isscalar (par) && isreal (par))) error (["ultrwin: ", upper (types(type)), " must be a real scalar"]); elseif (! (isscalar (norm) && norm == fix (norm) && norm >= 0)) # Alt. norms; WIP error ("ultrwin: NORM must be a non-negative integer"); endif [w, xmu] = __ultrwin__(m, mu, par, type-1, norm); endfunction %!test %! assert(ultrwin(100, 1, 1), ones(100, 1), 1e-14); %!test %! L = 201; xmu = 1.01; m = L-1; %! for mu = -1.35:.3:1.35 %! x = xmu*cos([0:m]*pi/L); %! C(2,:) = 2*mu*x; C(1,:) = 1; %! for k = 2:m; C(k+1,:) = 2*(k+mu-1)/k*x.*C(k,:) - (k+2*mu-2)/k*C(k-1,:); end %! b = real(ifft(C(m+1,:))); b = b(m/2+2:L)/b(1); %! assert(ultrwin(L, mu, xmu, "x")', [b 1 fliplr(b)], 1e-12); %! end %!test %! b = [ %! 5.7962919401511820e-03 %! 1.6086991349967078e-02 %! 3.6019014684117417e-02 %! 6.8897525451558125e-02 %! 1.1802364384553447e-01 %! 1.8566749737411145e-01 %! 2.7234740630826737e-01 %! 3.7625460141456091e-01 %! 4.9297108901880221e-01 %! 6.1558961695849457e-01 %! 7.3527571856983598e-01 %! 8.4222550739092694e-01 %! 9.2688779484512085e-01 %! 9.8125497127708561e-01]'; %! [w xmu] = ultrwin(29, 0, 3); %! assert(w', [b 1 fliplr(b)], 1e-14); %! assert(xmu, 1.053578297819277, 1e-14); %!test %! b = [ %! 2.9953636903962466e-02 %! 7.6096450051659603e-02 %! 1.5207129867916891e-01 %! 2.5906995366355179e-01 %! 3.9341065451220536e-01 %! 5.4533014012036929e-01 %! 6.9975915071207051e-01 %! 8.3851052636906720e-01 %! 9.4345733548690369e-01]'; %! assert(ultrwin(20, .5, 50, "a")', [b 1 1 fliplr(b)], 1e-14); %!test %! b = [ %! 1.0159906492322712e-01 %! 1.4456358609406283e-01 %! 2.4781689516201011e-01 %! 3.7237015168857646e-01 %! 5.1296973026690407e-01 %! 6.5799041448113671e-01 %! 7.9299087042967320e-01 %! 9.0299778924260576e-01 %! 9.7496213649820296e-01]'; %! assert(ultrwin(19, -.4, 40, "l")', [b 1 fliplr(b)], 1e-14); %!demo %! w=ultrwin(120, -1, 40, "l"); [W,f]=freqz(w); clf %! subplot(2,1,1); plot(f/pi, 20*log10(W/abs(W(1)))); grid; axis([0 1 -90 0]) %! subplot(2,1,2); plot(0:length(w)-1, w); grid %! %----------------------------------------------------------- %! % Figure shows an Ultraspherical window with MU=-1, LATT=40: %! % frequency domain above, time domain below. %!demo %! c="krbm"; clf; subplot(2, 1, 1) %! for beta=2:5 %! w=ultrwin(80, -.5, beta); [W,f]=freqz(w); %! plot(f/pi, 20*log10(W/abs(W(1))), c(1+mod(beta, length(c)))); hold on %! end; grid; axis([0 1 -140 0]); hold off %! subplot(2, 1, 2); %! for n=2:10 %! w=ultrwin(n*20, 1, 3); [W,f]=freqz(w,1,2^11); %! plot(f/pi, 20*log10(W/abs(W(1))), c(1+mod(n, length(c)))); hold on %! end; grid; axis([0 .2 -100 0]); hold off %! %-------------------------------------------------- %! % Figure shows transfers of Ultraspherical windows: %! % above: varying BETA with fixed N & MU, %! % below: varying N with fixed MU & BETA. %!demo %! c="krbm"; clf; subplot(2, 1, 1) %! for j=0:4 %! w=ultrwin(80, j*.6-1.2, 50, "a"); [W,f]=freqz(w); %! plot(f/pi, 20*log10(W/abs(W(1))), c(1+mod(j, length(c)))); hold on %! end; grid; axis([0 1 -100 0]); hold off %! subplot(2, 1, 2); %! for j=4:-1:0 %! w=ultrwin(80, j*.75-1.5, 50, "l"); [W,f]=freqz(w); %! plot(f/pi, 20*log10(W/abs(W(1))), c(1+mod(j, length(c)))); hold on %! end; grid; axis([0 1 -100 0]); hold off %! %-------------------------------------------------- %! % Figure shows transfers of Ultraspherical windows: %! % above: varying MU with fixed N & ATT, %! % below: varying MU with fixed N & LATT. %!demo %! clf; a=[.8 2 -115 5]; fc=1.1/pi; l="labelxy"; %! for k=1:3; switch (k); case 1; w=kaiser(L=159, 7.91); %! case 2; w=ultrwin(L=165, 0, 2.73); case 3; w=ultrwin(L=153, .5, 2.6); end %! subplot(3, 1, 4-k); f=[1:(L-1)/2]*pi;f=sin(fc*f)./f; f=[fliplr(f) fc f]'; %! [h,f]=freqz(w.*f,1,2^14); plot(f,20*log10(h)); grid; axis(a,l); l="labely"; %! end %! %----------------------------------------------------------- %! % Figure shows example lowpass filter design (Fp=1, Fs=1.2 %! % rad/s, att=80 dB) and comparison with other windows. From %! % top to bottom: Ultraspherical, Dolph-Chebyshev, and Kaiser %! % windows, with lengths 153, 165, and 159 respectively. signal-1.4.5/inst/unshiftdata.m0000644000000000000000000000431014456505401014633 0ustar0000000000000000## Copyright (C) 2014 Georgios Ouzounis ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{out}] =} unshiftdata (@var{in}, @var{perm}, @var{shifts}) ## Reverse what is done by shiftdata. ## @seealso{shiftdata} ## @end deftypefn function out = unshiftdata (in, perm, shifts) if (nargin != 3) print_usage (); endif if (! isempty (perm)) if (perm != fix (perm)) error ("unshiftdata: PERM must be a vector of integers"); endif dim = perm(1); elseif (! isempty (shifts)) if (shifts != fix (shifts)) error ("unshiftdata: SHIFTS must be an integer"); endif dim = shifts + 1; else error ("unshiftdata: Either PERM or SHIFTS must not be empty"); endif out = ipermute (in, [dim 1: (dim - 1) (dim + 1): (length (size (in)))]); endfunction %!test %! x = 1:5; %! [y, perm, shifts] = shiftdata (x); %! x2 = unshiftdata (y, perm, shifts); %! assert (x, x2); %!test %! X = fix (rand (3, 3) * 100); %! [Y, perm, shifts] = shiftdata (X, 2); %! X2 = unshiftdata (Y, perm, shifts); %! assert (X, X2); %!test %! X = fix (rand (4, 4, 4, 4) * 100); %! [Y, perm, shifts] = shiftdata (X, 3); %! X2 = unshiftdata (Y, perm, shifts); %! assert (X, X2); %!test %! X = fix (rand (1, 1, 3, 4) * 100); %! [Y, perm, shifts] = shiftdata (X); %! X2 = unshiftdata (Y, perm, shifts); %! assert (X, X2); ## Test input validation %!error unshiftdata () %!error unshiftdata (1, 2) %!error unshiftdata (1, 2, 3, 4) %!error unshiftdata (1, 2.5) %!error unshiftdata (1, [], 2.5) %!error unshiftdata (1, [], []) signal-1.4.5/inst/upsample.m0000644000000000000000000000242214456505401014151 0ustar0000000000000000## Author: Paul Kienzle (2007) ## This program is granted to the public domain. ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} upsample (@var{x}, @var{n}) ## @deftypefnx {Function File} {@var{y} =} upsample (@var{x}, @var{n}, @var{offset}) ## Upsample the signal, inserting @var{n}-1 zeros between every element. ## ## If @var{x} is a matrix, upsample every column. ## ## If @var{offset} is specified, control the position of the inserted sample in ## the block of @var{n} zeros. ## @seealso{decimate, downsample, interp, resample, upfirdn} ## @end deftypefn function y = upsample (x, n, phase = 0) if nargin<2 || nargin>3, print_usage; endif if phase > n - 1 warning("This is incompatible with Matlab (phase = 0:n-1). See octave-forge signal package release notes for details." ) endif [nr,nc] = size(x); if any([nr,nc]==1), y = zeros(n*nr*nc,1); y(phase + 1:n:end) = x; if nr==1, y = y.'; endif else y = zeros(n*nr,nc); y(phase + 1:n:end,:) = x; endif endfunction %!assert(upsample([1,3,5],2),[1,0,3,0,5,0]); %!assert(upsample([1;3;5],2),[1;0;3;0;5;0]); %!assert(upsample([1,2;5,6;9,10],2),[1,2;0,0;5,6;0,0;9,10;0,0]); %!assert(upsample([2,4],2,1),[0,2,0,4]); %!assert(upsample([3,4;7,8],2,1),[0,0;3,4;0,0;7,8]); signal-1.4.5/inst/upsamplefill.m0000644000000000000000000000537414456505401015031 0ustar0000000000000000## Copyright (C) 2013 Juan Pablo Carbajal ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} upsamplefill (@var{x}, @var{v}) ## @deftypefnx {Function File} {@var{y} =} upsamplefill (@dots{}, @var{copy}) ## Upsamples a vector interleaving given values or copies of the vector elements. ## ## The values in the vector @var{v} are placed between the elements of @var{x}. ## ## If the optional argument @var{copy} is @var{true} then @var{v} should be a ## scalar and each value in @var{x} are repeat @var{v} times. ## ## Example: ## @example ## @group ## upsamplefill (eye (2), 2, true) ## @result{} 1 0 ## 1 0 ## 1 0 ## 0 1 ## 0 1 ## 0 1 ## upsamplefill (eye (2), [-1 -1 -1]) ## @result{} 1 0 ## -1 -1 ## -1 -1 ## -1 -1 ## 0 1 ## -1 -1 ## -1 -1 ## -1 -1 ## @end group ## @end example ## ## @seealso{upsample} ## @end deftypefn ## Author: Juan Pablo Carbajal function y = upsamplefill (x, v, copy=false) if nargin<2 print_usage; end [nr,nc] = size (x); if copy if any ([nr,nc]==1) y = kron (x(:), ones(v+1,1)); if nr == 1 y = y.'; endif else y = kron (x, ones(v+1,1)); endif return else % Assumes 'v' row or column vector n = length(v) + 1; N = n*nr; if any ([nr,nc]==1) N = N*nc; idx = 1:n:N; idx_c = setdiff (1:N, 1:n:N); y = zeros (N,1); y(idx) = x; y(idx_c) = repmat (v(:), max(nr,nc), 1); if nr == 1 y = y.'; endif else idx = 1:n:N; idx_c = setdiff(1:N,1:n:N); y = zeros (N,nc); y(idx,:) = x; y(idx_c,:) = repmat (v(:), nr, nc); endif endif endfunction %!assert(upsamplefill([1,3,5],2),[1,2,3,2,5,2]); %!assert(upsamplefill([1;3;5],2),[1;2;3;2;5;2]); %!assert(upsamplefill([1,2,5],[2 -2]),[1,2,-2,2,2,-2,5,2,-2]); %!assert(upsamplefill(eye(2),2,true),[1,0;1,0;1,0;0,1;0,1;0,1]); %!assert(upsamplefill([1,3,5],2,true),[1,1,1,3,3,3,5,5,5]); %!assert(upsamplefill([1;3;5],2,true),[1;1;1;3;3;3;;5;5;5]); signal-1.4.5/inst/vco.m0000644000000000000000000000573614456505401013125 0ustar0000000000000000## Copyright (C) 2019-2023 The Octave Project Developers ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {} {y =} vco (@var{x}, @var{fc}, @var{fs}) ## @deftypefnx {} {y =} vco (@var{x}, [@var{fmin}, @var{fmax}], @var{fs}) ## Creates a signal that oscillates at a frequency determined by input @var{x} with a sampling frequency @var{fs}. ## ## Inputs: ## @itemize ## @item ## @var{x} - input data with a range of -1 to 1. A value of -1 means no output, 0 cuoreesponds to @var{fc}, ## and 1 corresponds to 2*@var{fc}. ## ## @item ## @var{fc} - Carrier frequency ## ## @item ## @var{fs} - Sampling rate ## ## @item ## @var{fmin}, @var{fmax} - Frequency modulation range limits. ## @end itemize ## ## Outputs: ## @itemize ## @item ## @var{y} - output signal ## @end itemize ## @end deftypefn function [y,yn] = vco (x, fc = [], fs = []) if (nargin < 1 || nargin > 3) print_usage (); endif ## We can't just set default values in parameter list because ## default FC depends on value of FS and empty arguments may be ## used to request default values. if (isvector (x) && rows (x) == 1) x = x(:); endif if (any (x(:) > 1 | x(:) < -1)) error ("vco: values in X must be in the range [-1, 1]"); endif if (isempty (fs)) fs = 1; endif if (isempty (fc)) fc = fs / 4; endif x_max = max (max (abs (x))); if (numel (fc) == 2) fmin = fc(1); fmax = fc(2); if (fmin > fs/2 || fmax > fs/2) error ("vco: FMIN and FMAX must be less than FS/2"); endif if (fmin >= fmax) error ("vco: FMAX must be greater than FMIN"); endif if (fmin < 0 || fmax < 0) error ("vco: FMIN and FMAX must be positive values"); endif ## I don't know whether this is the best way, but I think it gives ## the proper value for fc and the proper deviation (+/-) from ## that value. fc = (fmin + fmax) / 2; kf = (fmax - fmin) / 2 / fs * 2 * pi / x_max; elseif (isscalar (fc)) kf = (fc / fs) * 2 * pi / x_max; else error ("vco: FC must be a scalar"); endif if (! (isscalar (fs))) error ("vco: FS must be a scalar"); endif ## Note, no need to generate a matrix for T, we can rely on ## broadcasting instead. len = rows (x); t = (0 : (1/fs) : ((len-1)/fs))'; ## Use modulate instead? y = cos (2*pi*fc*t + kf*cumsum (x)); endfunction %!error vco %!error vco([1 2]) signal-1.4.5/inst/wconv.m0000644000000000000000000000341214456505401013457 0ustar0000000000000000## Copyright (C) 2013 Lukas F. Reichlin ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} wconv (@var{type}, @var{x}, @var{f}) ## @deftypefnx {Function File} {@var{y} =} wconv (@var{type}, @var{x}, @var{f}, @var{shape}) ## 1-D or 2-D convolution. ## ## @strong{Inputs} ## @table @var ## @item type ## Type of convolution. ## @item x ## Signal vector or matrix. ## @item f ## Coefficients of @acronym{FIR} filter. ## @item shape ## Shape. ## @end table ## ## @strong{Outputs} ## @table @var ## @item y ## Convoluted signal. ## @end table ## @end deftypefn ## Author: Lukas Reichlin ## Created: April 2013 ## Version: 0.1 function y = wconv (type, x, f, shape = "full") if (nargin < 3 || nargin > 4) print_usage (); endif switch (type(1)) case {1, "1"} y = conv2 (x(:).', f(:).', shape); if (rows (x) > 1) y = y.'; endif case {2, "2"} y = conv2 (x, f, shape); case "r" y = conv2 (x, f(:).', shape); case "c" y = conv2 (x.', f(:).', shape); y = y.'; otherwise print_usage (); endswitch endfunction signal-1.4.5/inst/welchwin.m0000644000000000000000000000735114456505401014151 0ustar0000000000000000## Copyright (C) 2007 Muthiah Annamalai ## Copyright (C) 2008-2009 Mike Gross ## Copyright (C) 2008-2009 Peter V. Lanspeary ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} welchwin (@var{m}) ## @deftypefnx {Function File} {} welchwin (@var{m}, "periodic") ## @deftypefnx {Function File} {} welchwin (@var{m}, "symmetric") ## Return the filter coefficients of a Welch window of length @var{m}. The ## Welch window is given by ## @var{w}(n)=1-(n/N-1)^2, n=[0,1, ... @var{m}-1]. ## The optional argument specifies a "symmetric" window (the default) or a ## "periodic" window. ## ## A symmetric window has zero at each end and maximum in the middle, and the ## length must be an integer greater than 2. The variable @var{N} in the ## formula above is @code{(@var{m}-1)/2}. ## ## A periodic window wraps around the cyclic interval [0,1, ... @var{m}-1], ## and is intended for use with the DFT. The length must be an integer ## greater than 1. The variable @var{N} in the formula above is ## @code{@var{m}/2}. ## ## @seealso{blackman, kaiser} ## @end deftypefn function w = welchwin (m, opt) if (nargin < 1 || nargin > 2) print_usage (); elseif (! (isscalar (m) && (m == fix (m)) && (m > 0))) error ("welchwin: M must be a positive integer"); endif N = (m - 1) / 2; mmin = 3; if (nargin == 2) switch (opt) case "periodic" N = m / 2; mmin = 2; case "symmetric" N = (m - 1) / 2; otherwise error ("welchwin: window type must be either \"periodic\" or \"symmetric\""); endswitch endif ## Periodic window is not properly defined for m < 2. ## Symmetric window is not properly defined for m < 3. if (m < mmin) error ("welchwin: M must be an integer greater than %d", mmin); endif n = [0:m-1]'; w = 1 - ((n-N)./N).^2; endfunction %!demo %! m = 32; %! t = [0:m-1]; %! printf ("Graph: single period of "); %! printf ("%d-point periodic (blue) and symmetric (red) windows\n", m); %! xp = welchwin (m, "periodic"); %! xs = welchwin (m, "symmetric"); %! plot (t, xp, "b", t, xs, "r") %!demo %! m = 32; %! t = [0:4*m-1]; %! printf ("Graph: 4 periods of "); %! printf ("%d-point periodic (blue) and symmetric (red) windows\n", m); %! xp = welchwin (m, "periodic"); %! xs = welchwin (m, "symmetric"); %! xp2 = repmat (xp, 4, 1); %! xs2 = repmat (xs, 4, 1); %! plot (t, xp2, "b", t, xs2, "r") %!demo %! m = 32; %! n = 512; %! xp = welchwin (m, "periodic"); %! s = fftshift (max (1e-2, abs (fft (postpad (xp, n))))); %! f = [-0.5:1/n:0.5-1/n]; %! printf ("%dx null-padded, power spectrum of %d-point window\n", n/m, m); %! semilogy (f, s) %!assert (welchwin (3), [0; 1; 0]); %!assert (welchwin (15), flipud (welchwin (15))); %!assert (welchwin (16), flipud (welchwin (16))); %!assert (welchwin (15), welchwin (15, "symmetric")); %!assert (welchwin (16)(1:15), welchwin (15, "periodic")); %% Test input validation %!error welchwin () %!error welchwin (0.5) %!error welchwin (-1) %!error welchwin (ones (1, 4)) %!error welchwin (1, 2, 3) %!error welchwin (1, "invalid") signal-1.4.5/inst/window.m0000644000000000000000000000321314456505401013631 0ustar0000000000000000## Copyright (C) 2008 David Bateman ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{w} =} window (@var{f}, @var{m}) ## @deftypefnx {Function File} {@var{w} =} window (@var{f}, @var{m}, @var{opts}) ## Create an @var{m}-point window from the function @var{f}. The function ## @var{f} can be for example @code{@@blackman}. Any additional ## arguments @var{opt} are passed to the windowing function. ## @end deftypefn function wout = window (f, m, varargin) if (nargin == 0) error ("window: UI tool not supported"); elseif (nargin < 2) print_usage (); else w = feval (f, m, varargin{:}); if (nargout > 0) wout = w; endif endif endfunction %!assert (window (@bartlett, 16), window ("bartlett", 16)) %!assert (window (@hamming, 16), window ("hamming", 16)) %!assert (window (@hanning, 16), window ("hanning", 16)) %!assert (window (@triang, 16), window ("triang", 16)) %% Test input validation %!error window () %!error window (1) %!error window ("hanning") signal-1.4.5/inst/wkeep.m0000644000000000000000000000362314456505401013442 0ustar0000000000000000## Copyright (C) 2008 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} wkeep (@var{x}, @var{l}) ## @deftypefnx {Function File} {@var{y} =} wkeep (@var{x}, @var{l}, @var{opt}) ## Extract the elements of @var{x} of size @var{l} from the center, the right ## or the left. ## @end deftypefn function y = wkeep(x,l,opt = 'c') if (nargin < 2|| nargin > 3); print_usage; endif if(isvector(x)) if(l > length(x)) error('l must be or equal the size of x'); endif if(opt=='c') s = (length(x)-l)./2; y = x(1+floor(s):end-ceil(s)); elseif(opt=='l') y=x(1:l); elseif(opt=='r') y = x(end-l+1:end); else error('opt must be equal to c, l or r'); endif else if(length(l) == 2) s1 = (length(x)-l(1))./2; s2 = (length(x)-l(2))./2; else error('For a matrix l must be a 1x2 vector'); endif if(nargin==2) y = x(1+floor(s1):end-ceil(s1),1+floor(s2):end-ceil(s2)); else if(length(opt) == 2) firstr=opt(1); firstc=opt(2); else error('For a matrix l must be a 1x2 vector'); endif y=x(firstr:firstr+l(1)-1,firstc:firstc+l(2)-1); endif endif endfunction signal-1.4.5/inst/wrev.m0000644000000000000000000000213414456505401013306 0ustar0000000000000000## Copyright (C) 2008 Sylvain Pelissier ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{y} =} wrev (@var{x}) ## Reverse the order of the element of the vector @var{x}. ## @seealso{flipud, fliplr} ## @end deftypefn function y = wrev(x) if (nargin < 1|| nargin > 1); print_usage; endif if(~isvector(x)) error('x must be a vector'); endif l = length(x); k = 0:l-1; y = x(l-k); endfunction signal-1.4.5/inst/xcorr.m0000644000000000000000000003223014456505401013460 0ustar0000000000000000## Copyright (C) 1999-2001 Paul Kienzle ## Copyright (C) 2004 ## Copyright (C) 2008, 2010 Peter Lanspeary ## Copyright (C) 2022 Octave-Forge community ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{R}, @var{lag}] =} xcorr ( @var{X} ) ## @deftypefnx {Function File} {@dots{} =} xcorr ( @var{X}, @var{Y} ) ## @deftypefnx {Function File} {@dots{} =} xcorr ( @dots{}, @var{maxlag}) ## @deftypefnx {Function File} {@dots{} =} xcorr ( @dots{}, @var{scale}) ## Estimates the cross-correlation. ## ## Estimate the cross correlation R_xy(k) of vector arguments @var{X} and @var{Y} ## or, if @var{Y} is omitted, estimate autocorrelation R_xx(k) of vector @var{X}, ## for a range of lags k specified by argument "maxlag". If @var{X} is a ## matrix, each column of @var{X} is correlated with itself and every other ## column. ## ## The cross-correlation estimate between vectors "x" and "y" (of ## length N) for lag "k" is given by ## ## @tex ## $$ R_{xy}(k) = \sum_{i=1}^{N} x_{i+k} \conj(y_i), ## @end tex ## @ifnottex ## @example ## @group ## N ## R_xy(k) = sum x_@{i+k@} conj(y_i), ## i=1 ## @end group ## @end example ## @end ifnottex ## ## where data not provided (for example x(-1), y(N+1)) is zero. Note the ## definition of cross-correlation given above. To compute a ## cross-correlation consistent with the field of statistics, see @command{xcov}. ## ## @strong{ARGUMENTS} ## @table @var ## @item X ## [non-empty; real or complex; vector or matrix] data ## ## @item Y ## [real or complex vector] data ## ## If @var{X} is a matrix (not a vector), @var{Y} must be omitted. ## @var{Y} may be omitted if @var{X} is a vector; in this case xcorr ## estimates the autocorrelation of @var{X}. ## ## @item maxlag ## [integer scalar] maximum correlation lag ## If omitted, the default value is N-1, where N is the ## greater of the lengths of @var{X} and @var{Y} or, if @var{X} is a matrix, ## the number of rows in @var{X}. ## ## @item scale ## [character string] specifies the type of scaling applied ## to the correlation vector (or matrix). is one of: ## @table @samp ## @item none ## return the unscaled correlation, R, ## @item biased ## return the biased average, R/N, ## @item unbiased ## return the unbiased average, R(k)/(N-|k|), ## @item coeff or normalized ## return the correlation coefficient, R/(rms(x).rms(y)), ## where "k" is the lag, and "N" is the length of @var{X}. ## If omitted, the default value is "none". ## If @var{Y} is supplied but does not have the same length as @var{X}, ## scale must be "none". ## @end table ## @end table ## ## @strong{RETURNED VARIABLES} ## @table @var ## @item R ## array of correlation estimates ## @item lag ## row vector of correlation lags [-maxlag:maxlag] ## @end table ## ## The array of correlation estimates has one of the following forms: ## (1) Cross-correlation estimate if @var{X} and @var{Y} are vectors. ## ## (2) Autocorrelation estimate if is a vector and @var{Y} is omitted. ## ## (3) If @var{X} is a matrix, R is an matrix containing the cross-correlation ## estimate of each column with every other column. Lag varies with the first ## index so that R has 2*maxlag+1 rows and P^2 columns where P is the number of ## columns in @var{X}. ## ## If Rij(k) is the correlation between columns i and j of @var{X} ## ## @code{R(k+maxlag+1,P*(i-1)+j) == Rij(k)} ## ## for lag k in [-maxlag:maxlag], or ## ## @code{R(:,P*(i-1)+j) == xcorr(X(:,i),X(:,j))}. ## ## @code{reshape(R(k,:),P,P)} is the cross-correlation matrix for @code{X(k,:)}. ## ## @seealso{xcov} ## @end deftypefn ## The cross-correlation estimate is calculated by a "spectral" method ## in which the FFT of the first vector is multiplied element-by-element ## with the FFT of second vector. The computational effort depends on ## the length N of the vectors and is independent of the number of lags ## requested. If you only need a few lags, the "direct sum" method may ## be faster: ## ## Ref: Stearns, SD and David, RA (1988). Signal Processing Algorithms. ## New Jersey: Prentice-Hall. ## unbiased: ## ( hankel(x(1:k),[x(k:N); zeros(k-1,1)]) * y ) ./ [N:-1:N-k+1](:) ## biased: ## ( hankel(x(1:k),[x(k:N); zeros(k-1,1)]) * y ) ./ N ## ## If length(x) == length(y) + k, then you can use the simpler ## ( hankel(x(1:k),x(k:N-k)) * y ) ./ N function [R, lags] = xcorr (X, varargin) if (nargin < 1 || nargin > 4) print_usage; endif ## assign optional arguments according to data type maxlag=[]; scale=[]; Y=[]; for idx=1:length(varargin) arg = varargin{idx}; if ischar(arg) if isempty(scale) scale = arg; else error ("xcorr: unexpected char value '%s' when scale is already set to '%s'", arg, scale); endif elseif isscalar(arg) if isempty(maxlag) maxlag = arg; else error ("xcorr: unexpected scalar value '%f' when maxlag is already set to '%f'", arg, maxlag); endif elseif idx == 1 Y = arg; elseif (! isempty (arg)) error ("xcorr: unknown optional input variable at position %d", idx); endif endfor ## assign defaults to missing arguments if isvector(X) ## if isempty(Y), Y=X; endif ## this line disables code for autocorr'n N = max(length(X),length(Y)); else N = rows(X); endif if isempty(maxlag), maxlag=N-1; endif if isempty(scale), scale='none'; endif ## check argument values if isempty(X) || isscalar(X) || ! ismatrix(X) error("xcorr: X must be a vector or matrix"); endif if isscalar(Y) || ischar(Y) || (!isempty(Y) && !isvector(Y)) error("xcorr: Y must be a vector"); endif if !isempty(Y) && !isvector(X) error("xcorr: X must be a vector if Y is specified"); endif if !isscalar(maxlag) || !isreal(maxlag) || maxlag<0 || fix(maxlag)!=maxlag error("xcorr: maxlag must be a single non-negative integer"); endif ## ## sanity check on number of requested lags ## Correlations for lags in excess of +/-(N-1) ## (a) are not calculated by the FFT algorithm, ## (b) are all zero; so provide them by padding ## the results (with zeros) before returning. if (maxlag > N-1) pad_result = maxlag - (N - 1); maxlag = N - 1; %error("xcorr: maxlag must be less than length(X)"); else pad_result = 0; endif if isvector(X) && isvector(Y) && length(X) != length(Y) && ... !strcmp(scale,'none') error("xcorr: scale must be 'none' if length(X) != length(Y)") endif P = columns(X); M = 2^nextpow2(N + maxlag); if !isvector(X) ## For matrix X, correlate each column "i" with all other "j" columns R = zeros(2*maxlag+1,P^2); ## do FFTs of padded column vectors pre = fft (postpad (prepad (X, N+maxlag), M) ); post = conj (fft (postpad (X, M))); ## do autocorrelations (each column with itself) ## -- if result R is reshaped to 3D matrix (i.e. R=reshape(R,M,P,P)) ## the autocorrelations are on leading diagonal columns of R, ## where i==j in R(:,i,j) cor = ifft (post .* pre); R(:, 1:P+1:P^2) = cor (1:2*maxlag+1,:); ## do the cross correlations ## -- these are the off-diagonal column of the reshaped 3D result ## matrix -- i!=j in R(:,i,j) for i=1:P-1 j = i+1:P; cor = ifft( pre(:,i*ones(length(j),1)) .* post(:,j) ); R(:,(i-1)*P+j) = cor(1:2*maxlag+1,:); R(:,(j-1)*P+i) = conj( flipud( cor(1:2*maxlag+1,:) ) ); endfor elseif isempty(Y) ## compute autocorrelation of a single vector post = fft( postpad(X(:),M) ); cor = ifft( post .* conj(post) ); R = [ conj(cor(maxlag+1:-1:2)) ; cor(1:maxlag+1) ]; else ## compute cross-correlation of X and Y ## If one of X & Y is a row vector, the other can be a column vector. pre = fft( postpad( prepad( X(:), length(X)+maxlag ), M) ); post = fft( postpad( Y(:), M ) ); cor = ifft( pre .* conj(post) ); R = cor(1:2*maxlag+1); endif ## if inputs are real, outputs should be real, so ignore the ## insignificant complex portion left over from the FFT if isreal(X) && (isempty(Y) || isreal(Y)) R=real(R); endif ## correct for bias if strcmp(scale, 'biased') R = R ./ N; elseif strcmp(scale, 'unbiased') R = R ./ ( [ N-maxlag:N-1, N, N-1:-1:N-maxlag ]' * ones(1,columns(R)) ); elseif strcmp(scale, 'coeff') || strcmp(scale, 'normalized') ## R = R ./ R(maxlag+1) works only for autocorrelation ## For cross correlation coeff, divide by rms(X)*rms(Y). if !isvector(X) ## for matrix (more than 1 column) X rms = sqrt( sumsq(X) ); R = R ./ ( ones(rows(R),1) * reshape(rms.'*rms,1,[]) ); elseif isempty(Y) ## for autocorrelation, R(zero-lag) is the mean square. R = R / R(maxlag+1); else ## for vectors X and Y R = R / sqrt( sumsq(X)*sumsq(Y) ); endif elseif !strcmp(scale, 'none') error("xcorr: scale must be 'biased', 'unbiased', 'coeff' or 'none'"); endif ## Pad result if necessary ## (most likely is not required, use "if" to avoid unnecessary code) ## At this point, lag varies with the first index in R; ## so pad **before** the transpose. if pad_result R_pad = zeros(pad_result,columns(R)); R = [R_pad; R; R_pad]; endif ## Correct the shape (transpose) so it is the same as the first input vector if isvector(X) && P > 1 R = R.'; endif ## return the lag indices if desired if nargout == 2 maxlag += pad_result; lags = [-maxlag:maxlag]; endif endfunction ##------------ Use brute force to compute the correlation ------- ##if !isvector(X) ## ## For matrix X, compute cross-correlation of all columns ## R = zeros(2*maxlag+1,P^2); ## for i=1:P ## for j=i:P ## idx = (i-1)*P+j; ## R(maxlag+1,idx) = X(:,i)' * X(:,j); ## for k = 1:maxlag ## R(maxlag+1-k,idx) = X(k+1:N,i)' * X(1:N-k,j); ## R(maxlag+1+k,idx) = X(1:N-k,i)' * X(k+1:N,j); ## endfor ## if (i!=j), R(:,(j-1)*P+i) = conj(flipud(R(:,idx))); endif ## endfor ## endfor ##elseif isempty(Y) ## ## reshape X so that dot product comes out right ## X = reshape(X, 1, N); ## ## ## compute autocorrelation for 0:maxlag ## R = zeros (2*maxlag + 1, 1); ## for k=0:maxlag ## R(maxlag+1+k) = X(1:N-k) * X(k+1:N)'; ## endfor ## ## ## use symmetry for -maxlag:-1 ## R(1:maxlag) = conj(R(2*maxlag+1:-1:maxlag+2)); ##else ## ## reshape and pad so X and Y are the same length ## X = reshape(postpad(X,N), 1, N); ## Y = reshape(postpad(Y,N), 1, N)'; ## ## ## compute cross-correlation ## R = zeros (2*maxlag + 1, 1); ## R(maxlag+1) = X*Y; ## for k=1:maxlag ## R(maxlag+1-k) = X(k+1:N) * Y(1:N-k); ## R(maxlag+1+k) = X(1:N-k) * Y(k+1:N); ## endfor ##endif ##-------------------------------------------------------------- %!shared x, y %! x = 0.5.^(0:15); %! y = circshift(x,5); ## Test input validation %!error xcorr () %!error xcorr (1) %!error xcorr (x, 1, x) %!error xcorr (x, 'none', x) %!error xcorr (x, x, 'invalid') %!error xcorr (x, 'invalid') %!test %! [c,lags] = xcorr(x); %! # largest spike at 0 lag, where X matches itself - ie the center %! [m, im] = max(c); %! assert(m, 4/3, 1e-6) %! assert(im, (numel(lags)+1)/2); %! %! [c1,lags1] = xcorr(x, x); %! [m, im] = max(c1); %! assert(m, 4/3, 1e-6) %! assert(im, (numel(lags1)+1)/2); %! assert(c1, c, 2*eps); %! assert(lags1, lags); %!test %! [c,lags] = xcorr(x,y); %! # largest spike at 0 lag, where X matches Y %! [m, im] = max(c); %! assert(m, 4/3, 1e-6) %! assert(lags(im), -5); %!test %! [c0,lags0] = xcorr(x,y); %! [c1,lags1] = xcorr(x,y, 'none'); %! assert(c0, c1); %! assert(lags0, lags1); %!test %! [c0,lags0] = xcorr(x,y); %! [c1,lags1] = xcorr(x,y, 'normalized'); %! assert(lags0, lags1); %! [m, im] = max(c1); %! # at 0 lag, should be 1 %! assert(m, 1, 1e-6); %! [c2,lags2] = xcorr(x,y, 'coeff'); %! assert(c1, c2); %! assert(lags1, lags2); %!test %! [c0,lags0] = xcorr(x,y); %! [c1,lags1] = xcorr(x,y, 'biased'); %! assert(lags0, lags1); %! [m, im] = max(c1); %! assert(m, 1/12, 1e-6); %! %! [c1,lags1] = xcorr(x, 'biased'); %! assert(lags0, lags1); %! [m, im] = max(c1); %! assert(m, 1/12, 1e-6); %!test %! [c0,lags0] = xcorr(x,y); %! [c1,lags1] = xcorr(x,y, 'unbiased'); %! assert(lags0, lags1); %! [m, im] = max(c1); %! assert(m, 1/8.25, 1e-6); %!test %! [c,lags] = xcorr(x,y, 10); %! [m, im] = max(c); %! assert(lags(im), -5); %! assert(lags(1), -10); %! assert(lags(end), 10); %! %! [c,lags] = xcorr(x,10); %! [m, im] = max(c); %! assert(lags(1), -10); %! assert(lags(end), 10); %!test %! [c0,lags0] = xcorr(x,y, 'normalized', 10); %! [c1,lags1] = xcorr(x,y, 10, 'normalized'); %! assert(c0, c1); %! assert(lags0, lags1); signal-1.4.5/inst/xcorr2.m0000644000000000000000000001132314456505401013542 0ustar0000000000000000## Copyright (C) 2000 Dave Cogdell ## Copyright (C) 2000 Paul Kienzle ## Copyright (C) 2012 CarnĂ« Draug ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} xcorr2 (@var{a}) ## @deftypefnx {Function File} {} xcorr2 (@var{a}, @var{b}) ## @deftypefnx {Function File} {} xcorr2 (@dots{}, @var{scale}) ## Compute the 2D cross-correlation of matrices @var{a} and @var{b}. ## ## If @var{b} is not specified, computes autocorrelation of @var{a}, i.e., ## same as @code{xcorr (@var{a}, @var{a})}. ## ## The optional argument @var{scale}, defines the type of scaling applied to the ## cross-correlation matrix. Possible values are: ## ## @table @asis ## @item "none" (default) ## No scaling. ## ## @item "biased" ## Scales the raw cross-correlation by the maximum number of elements of @var{a} ## and @var{b} involved in the generation of any element of @var{c}. ## ## @item "unbiased" ## Scales the raw correlation by dividing each element in the cross-correlation ## matrix by the number of products @var{a} and @var{b} used to generate that ## element. ## ## @item "coeff" ## Scales the normalized cross-correlation on the range of [0 1] so that a value ## of 1 corresponds to a correlation coefficient of 1. ## @end table ## ## @seealso{conv2, corr2, xcorr} ## @end deftypefn function c = xcorr2 (a, b, biasflag = "none") if (nargin < 1 || nargin > 3) print_usage; elseif (nargin == 2 && ischar (b)) biasflag = b; b = a; elseif (nargin == 1) ## we have to set this case here instead of the function line, because if ## someone calls the function with zero argument, since a is never set, we ## will fail with "`a' undefined" error rather that print_usage b = a; endif if (ndims (a) != 2 || ndims (b) != 2) error ("xcorr2: input matrices must must have only 2 dimensions"); endif ## compute correlation [ma,na] = size(a); [mb,nb] = size(b); c = conv2 (a, conj (b (mb:-1:1, nb:-1:1))); ## bias routines by Dave Cogdell (cogdelld@asme.org) ## optimized by Paul Kienzle (pkienzle@users.sf.net) ## coeff routine by CarnĂ« Draug (carandraug+dev@gmail.com) switch lower (biasflag) case {"none"} ## do nothing, it's all done case {"biased"} c = c / ( min ([ma, mb]) * min ([na, nb]) ); case {"unbiased"} lo = min ([na,nb]); hi = max ([na, nb]); row = [ 1:(lo-1), lo*ones(1,hi-lo+1), (lo-1):-1:1 ]; lo = min ([ma,mb]); hi = max ([ma, mb]); col = [ 1:(lo-1), lo*ones(1,hi-lo+1), (lo-1):-1:1 ]'; bias = col*row; c = c./bias; case {"coeff"} a = double (a); b = double (b); a = conv2 (a.^2, ones (size (b))); b = sumsq (b(:)); c(:,:) = c(:,:) ./ sqrt (a(:,:) * b); otherwise error ("xcorr2: invalid type of scale %s", biasflag); endswitch endfunction %!test # basic usage %! a = magic (5); %! b = [6 13 22; 10 18 23; 8 15 23]; %! c = [391 807 519 391 473 289 120 %! 920 1318 1045 909 1133 702 278 %! 995 1476 1338 1534 2040 1161 426 %! 828 1045 1501 2047 2108 1101 340 %! 571 1219 2074 2155 1896 821 234 %! 473 1006 1643 1457 946 347 108 %! 242 539 850 477 374 129 54]; %! assert (xcorr2 (a, b), c); %!shared a, b, c, row_shift, col_shift %! row_shift = 18; %! col_shift = 20; %! a = randi (255, 30, 30); %! b = a(row_shift-10:row_shift, col_shift-7:col_shift); %! c = xcorr2 (a, b, "coeff"); %!assert (nthargout ([1 2], @find, c == max (c(:))), {row_shift, col_shift}); # should return exact coordinates %! m = rand (size (b)) > 0.5; %! b(m) = b(m) * 0.95; %! b(!m) = b(!m) * 1.05; %! c = xcorr2 (a, b, "coeff"); %!assert (nthargout ([1 2], @find, c == max (c(:))), {row_shift, col_shift}); # even with some small noise, should return exact coordinates %!test # coeff of autocorrelation must be same as negative of correlation by additive inverse %! a = 10 * randn (100, 100); %! auto = xcorr2 (a, "coeff"); %! add_in = xcorr2 (a, -a, "coeff"); %! assert ([min(auto(:)), max(auto(:))], -[max(add_in(:)), min(add_in(:))]); signal-1.4.5/inst/xcov.m0000644000000000000000000000650514456505401013310 0ustar0000000000000000## Copyright (C) 1999, 2001 Paul Kienzle ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{R}, @var{lag}] =} xcov ( @var{X} ) ## @deftypefnx {Function File} {@dots{} =} xcov ( @var{X}, @var{Y} ) ## @deftypefnx {Function File} {@dots{} =} xcov ( @dots{}, @var{maxlag}) ## @deftypefnx {Function File} {@dots{} =} xcov ( @dots{}, @var{scale}) ## Compute covariance at various lags [=correlation(x-mean(x),y-mean(y))]. ## ## @table @var ## @item X ## input vector ## @item Y ## if specified, compute cross-covariance between X and Y, ## otherwise compute autocovariance of X. ## @item maxlag ## is specified, use lag range [-maxlag:maxlag], ## otherwise use range [-n+1:n-1]. ## @item scale: ## @table @samp ## @item biased ## for covariance=raw/N, ## @item unbiased ## for covariance=raw/(N-|lag|), ## @item coeff ## for covariance=raw/(covariance at lag 0), ## @item none ## for covariance=raw ## @item none ## is the default. ## @end table ## @end table ## ## Returns the covariance for each lag in the range, plus an ## optional vector of lags. ## ## @seealso{xcorr} ## @end deftypefn function [retval, lags] = xcov (X, Y, maxlag, scale) if (nargin < 1 || nargin > 4) print_usage; endif if nargin==1 Y=[]; maxlag=[]; scale=[]; elseif nargin==2 maxlag=[]; scale=[]; if ischar(Y), scale=Y; Y=[]; elseif isscalar(Y), maxlag=Y; Y=[]; endif elseif nargin==3 scale=[]; if ischar(maxlag), scale=maxlag; maxlag=[]; endif if isscalar(Y), maxlag=Y; Y=[]; endif endif ## FIXME: should let center(Y) deal with [] ## [retval, lags] = xcorr(center(X), center(Y), maxlag, scale); if (!isempty(Y)) [retval, lags] = xcorr(center(X), center(Y), maxlag, scale); else [retval, lags] = xcorr(center(X), maxlag, scale); endif endfunction ## Test input validation %!error xcov () %!test %! x = 1:5; %! [c, l] = xcov(x); %! assert(c, [-4.0 -4.0 -1.0 4.0 10.0 4.0 -1.0 -4.0 -4.0], 2*eps) %! assert(l, [-4 -3 -2 -1 0 1 2 3 4]) %!test %! x = 1:5; %! y = 1:5; %! [c, l] = xcov(x,y); %! assert(c, [-4.0 -4.0 -1.0 4.0 10.0 4.0 -1.0 -4.0 -4.0], 2*eps) %! assert(l, [-4 -3 -2 -1 0 1 2 3 4]) %! %! y = 1; %! [c, l] = xcov(x,y); %! assert(c, [4.0 10.0 4.0], 2*eps) %! assert(l, [-1 0 1]) %!test %! x = 1:5; %! y = 1:5; %! # maxlag %! [c, l] = xcov(x,y, 2); %! assert(c, [-1.0 4.0 10.0 4.0 -1.0], 2*eps) %! assert(l, [-2 -1 0 1 2]) %!test %! x = 1:5; %! y = 1:5; %! # scale %! [c, l] = xcov(x,y, 'none'); %! assert(c, [-4.0 -4.0 -1.0 4.0 10.0 4.0 -1.0 -4.0 -4.0], 2*eps) %! assert(l, [-4 -3 -2 -1 0 1 2 3 4]) %! %! [c, l] = xcov(x,y, 'biased'); %! assert(c, [-0.8 -0.8 -0.2 0.8 2.0 0.8 -0.2 -0.8 -0.8], 2*eps) %! assert(l, [-4 -3 -2 -1 0 1 2 3 4]) signal-1.4.5/inst/zerocrossing.m0000644000000000000000000000433414456505401015056 0ustar0000000000000000## Copyright (C) 2008 Carlo de Falco ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{x0} =} zerocrossing (@var{x}, @var{y}) ## Estimates the points at which a given waveform y=y(x) crosses the ## x-axis using linear interpolation. ## @seealso{fzero, roots} ## @end deftypefn function retval = zerocrossing (x,y) x = x(:);y = y(:); crossing_intervals = (y(1:end-1).*y(2:end) <= 0); left_ends = (x(1:end-1))(crossing_intervals); right_ends = (x(2:end))(crossing_intervals); left_vals = (y(1:end-1))(crossing_intervals); right_vals = (y(2:end))(crossing_intervals); mid_points = (left_ends+right_ends)/2; zero_intervals = find(left_vals==right_vals); retval1 = mid_points(zero_intervals); left_ends(zero_intervals) = []; right_ends(zero_intervals) = []; left_vals(zero_intervals) = []; right_vals(zero_intervals) = []; retval2=left_ends-(right_ends-left_ends).*left_vals./(right_vals-left_vals); retval = union(retval1,retval2); endfunction %!test %! x = linspace(0,1,100); %! y = rand(1,100)-0.5; %! x0= zerocrossing(x,y); %! y0 = interp1(x,y,x0); %! assert(norm(y0,inf), 0, 100*eps) %!test %! x = linspace(0,1,100); %! y = rand(1,100)-0.5; %! y(10:20) = 0; %! x0= zerocrossing(x,y); %! y0 = interp1(x,y,x0); %! assert(norm(y0,inf), 0, 100*eps) %!demo %! x = linspace(0,1,100); %! y = rand(1,100)-0.5; %! x0= zerocrossing(x,y); %! y0 = interp1(x,y,x0); %! plot(x,y,x0,y0,'x') %!demo %! x = linspace(0,1,100); %! y = rand(1,100)-0.5; %! y(10:20) = 0; %! x0= zerocrossing(x,y); %! y0 = interp1(x,y,x0); %! plot(x,y,x0,y0,'x') signal-1.4.5/inst/zp2sos.m0000644000000000000000000001475714456505401013601 0ustar0000000000000000## Copyright (C) 2005 Julius O. Smith III ## Copyright (C) 2021-2022 Charles Praplan ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{sos}, @var{g}] =} zp2sos (@var{z}) ## @deftypefnx {Function File} {[@var{sos}, @var{g}] =} zp2sos (@var{z}, @var{p}) ## @deftypefnx {Function File} {[@var{sos}, @var{g}] =} zp2sos (@var{z}, @var{p}, @var{k}) ## @deftypefnx {Function File} {@var{sos} =} zp2sos (@dots{}) ## Convert filter poles and zeros to second-order sections. ## ## INPUTS: ## @itemize ## @item ## @var{z} = column-vector containing the filter zeros ## @item ## @var{p} = column-vector containing the filter poles ## @item ## @var{k} = overall filter gain factor. If not given the gain is assumed to be 1. ## @end itemize ## ## RETURNED: ## @itemize ## @item ## @var{sos} = matrix of series second-order sections, one per row: ## @example ## @var{sos} = [@var{B1}.' @var{A1}.'; ...; @var{BN}.' @var{AN}.'] ## @end example ## where ## @code{@var{B1}.' = [b0 b1 b2] and @var{A1}.' = [a0 a1 a2]} for ## section 1, etc. ## See @code{filter} for documentation of the second-order direct-form filter ## coefficients @var{B}i and %@var{A}i, i=1:N. ## ## @item ## @var{g} is the overall gain factor that effectively scales ## any one of the @var{B}i vectors. ## @end itemize ## ## If called with only one output argument, the overall filter gain is ## applied to the first second-order section in the matrix @var{sos}. ## ## EXAMPLE: ## @example ## [z, p, k] = tf2zp ([1 0 0 0 0 1], [1 0 0 0 0 .9]); ## [sos, g] = zp2sos (z, p, k) ## ## sos = ## 1.0000 0.6180 1.0000 1.0000 0.6051 0.9587 ## 1.0000 -1.6180 1.0000 1.0000 -1.5843 0.9587 ## 1.0000 1.0000 0 1.0000 0.9791 0 ## ## g = ## 1 ## @end example ## ## @seealso{sos2zp, sos2tf, tf2sos, zp2tf, tf2zp} ## @end deftypefn function [SOS,G] = zp2sos(z,p,k,DoNotCombineReal) if nargin<3, k=1; endif if nargin<2, p=[]; endif DoNotCombineReal = 0; [zc, zr] = cplxreal (z(:)); [pc, pr] = cplxreal (p(:)); nzc = length (zc); npc = length (pc); nzr = length (zr); npr = length (pr); if DoNotCombineReal # Handling complex conjugate poles for count = 1:npc SOS(count, 4:6) = [1, -2 * real(pc(count)), abs(pc(count))^2]; endfor # Handling real poles for count = 1:npr SOS(count + npc, 4:6) = [0, 1, -pr(count)]; endfor # Handling complex conjugate zeros for count = 1:nzc SOS(count, 1:3) = [1, -2 * real(zc(count)), abs(zc(count))^2]; endfor # Handling real zeros for count = 1:nzr SOS(count+nzc, 1:3) = [0, 1, -zr(count)]; endfor # Completing SOS if needed (sections without pole or zero) if npc + npr > nzc + nzr for count = nzc + nzr + 1 : npc + npr % sections without zero SOS(count, 1:3) = [0, 0, 1]; end else for count = npc + npr + 1 : nzc + nzr % sections without pole SOS(count, 4:6) = [0, 0, 1]; endfor endif else # Handling complex conjugate poles for count = 1:npc SOS(count, 4:6) = [1, -2 * real(pc(count)), abs(pc(count))^2]; endfor # Handling pair of real poles for count = 1:floor(npr/2) SOS(count+npc, 4:6) = [1, - pr(2 * count - 1) - pr(2 * count), pr(2 * count - 1) * pr(2 * count)]; endfor # Handling last real pole (if any) if mod (npr,2) == 1 SOS(npc + floor (npr / 2) + 1, 4:6)= [0, 1, -pr(end)]; endif # Handling complex conjugate zeros for count = 1:nzc SOS(count, 1:3)= [1, -2 * real(zc(count)), abs(zc(count))^2]; endfor # Handling pair of real zeros for count = 1:floor(nzr / 2) SOS(count+nzc, 1:3)= [1, - zr(2 * count - 1) - zr(2 * count), zr(2 * count - 1) * zr(2 * count)]; endfor # Handling last real zero (if any) if mod (nzr, 2) == 1 SOS(nzc + floor (nzr / 2) + 1, 1:3) = [0, 1, -zr(end)]; endif # Completing SOS if needed (sections without pole or zero) if npc + ceil(npr / 2) > nzc + ceil(nzr / 2) for count = nzc + ceil (nzr / 2) + 1 : npc + ceil (npr / 2) % sections without zero SOS(count, 1:3) = [0, 0, 1]; endfor else for count = npc + ceil(npr / 2) + 1:nzc + ceil (nzr / 2) % sections without pole SOS(count, 4:6) = [0, 0, 1]; endfor endif endif if ~exist ('SOS') SOS=[0, 0, 1, 0, 0, 1]; # leading zeros will be removed endif # Removing leading zeros if present in numerator and denominator for count = 1:size(SOS,1) B=SOS(count, 1:3); A=SOS(count, 4:6); while B(1)==0 && A(1)==0 A(1) = []; # faster than A = circshift(A,-1); A(3) = 0; # " B(1) = []; B(3) = 0; endwhile SOS(count,:) = [B,A]; endfor ## If no output argument for the overall gain, combine it into the ## first section. if (nargout < 2) SOS(1,1:3) = k * SOS(1,1:3); else G = k; endif %!test %! B=[1 0 0 0 0 1]; A=[1 0 0 0 0 .9]; %! [z,p,k] = tf2zp(B,A); %! [sos,g] = zp2sos(z,p,k); %! [Bh,Ah] = sos2tf(sos,g); %! assert({Bh,Ah},{B,A},100*eps); %!test %! sos = zp2sos ([]); %! assert (sos, [1, 0, 0, 1, 0, 0], 100*eps); %!test %! sos = zp2sos ([], []); %! assert (sos, [1, 0, 0, 1, 0, 0], 100*eps); %!test %! sos = zp2sos ([], [], 2); %! assert (sos, [2, 0, 0, 1, 0, 0], 100*eps); %!test %! [sos, g] = zp2sos ([], [], 2); %! assert (sos, [1, 0, 0, 1, 0, 0], 100*eps); %! assert (g, 2, 100*eps); %!test %! sos = zp2sos([], [0], 1); %! assert (sos, [0, 1, 0, 1, 0, 0], 100*eps); %!test %! sos = zp2sos([0], [], 1); %! assert (sos, [1, 0, 0, 0, 1, 0], 100*eps); %!test %! sos = zp2sos([-1-j -1+j], [-1-2j -1+2j], 10); %! assert (sos, [10, 20, 20, 1, 2, 5], 100*eps); signal-1.4.5/inst/zp2ss.m0000644000000000000000000000352614456505401013412 0ustar0000000000000000## Copyright (C) 1994, 1996, 2000, 2002, 2003, 2004, 2005, 2007 Auburn University ## Copyright (C) 2012 Lukas F. Reichlin ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} zp2ss (@var{z}, @var{p}, @var{k}) ## Conversion from zero / pole to state space. ## ## @strong{Inputs} ## @table @var ## @item z ## @itemx p ## Vectors of (possibly) complex poles and zeros of a transfer ## function. Complex values must come in conjugate pairs ## (i.e., @math{x+jy} in @var{z} means that @math{x-jy} is also in @var{z}). ## @item k ## Real scalar (leading coefficient). ## @end table ## ## @strong{Outputs} ## @table @var ## @item @var{a} ## @itemx @var{b} ## @itemx @var{c} ## @itemx @var{d} ## The state space system, in the form: ## @tex ## $$ \dot x = Ax + Bu $$ ## $$ y = Cx + Du $$ ## @end tex ## @ifnottex ## @example ## @group ## . ## x = Ax + Bu ## y = Cx + Du ## @end group ## @end example ## @end ifnottex ## @end table ## @end deftypefn ## Author: David Clem function [a, b, c, d, e] = zp2ss (varargin) if (nargin == 0) print_usage (); endif [a, b, c, d, e] = dssdata (zpk (varargin{:}), []); endfunction signal-1.4.5/inst/zp2tf.m0000644000000000000000000000272714456505401013400 0ustar0000000000000000## Copyright (C) 1996, 1998, 2000, 2002, 2004, 2005, 2007 Auburn University ## Copyright (C) 2012 Lukas F. Reichlin ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{num}, @var{den}] =} zp2tf (@var{z}, @var{p}, @var{k}) ## Converts zeros / poles to a transfer function. ## ## @strong{Inputs} ## @table @var ## @item z ## @itemx p ## Vectors of (possibly complex) poles and zeros of a transfer ## function. Complex values must appear in conjugate pairs. ## @item k ## Real scalar (leading coefficient). ## @end table ## @end deftypefn ## Author: A. S. Hodel ## (With help from students Ingram, McGowan.) function [num, den] = zp2tf (varargin) if (nargin == 0) print_usage (); endif [num, den] = tfdata (zpk (varargin{:}), "vector"); endfunction signal-1.4.5/inst/zplane.m0000644000000000000000000001254314456505401013621 0ustar0000000000000000## Copyright (C) 1999, 2001 Paul Kienzle ## Copyright (C) 2004 Stefan van der Walt ## Copyright (C) 2019 Mike Miller ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; see the file COPYING. If not, see ## . ## -*- texinfo -*- ## @deftypefn {Function File} {} zplane (@var{z}, @var{p}) ## @deftypefnx {Function File} {} zplane (@var{b}, @var{a}) ## Plot the poles and zeros on a complex plane. If the arguments are column ## vectors @var{z} and @var{p}, the complex zeros @var{z} and poles @var{p} ## are displayed. If the arguments are row vectors @var{b} and @var{a}, the ## zeros and poles of the transfer function represented by these filter ## coefficients are displayed. ## ## If @var{z} and @var{p} are matrices, the columns are distinct sets of zeros ## and poles and are displayed together in distinct colors. ## ## Note that due to the nature of the @code{roots} function, poles and zeros ## may be displayed as occurring around a circle rather than at a single ## point. ## ## The transfer function is ## ## @example ## @group ## B(z) b0 + b1 z^(-1) + b2 z^(-2) + ... + bM z^(-M) ## H(z) = ---- = -------------------------------------------- ## A(z) a0 + a1 z^(-1) + a2 z^(-2) + ... + aN z^(-N) ## ## b0 (z - z1) (z - z2) ... (z - zM) ## = -- z^(-M+N) ------------------------------ ## a0 (z - p1) (z - p2) ... (z - pN) ## @end group ## @end example ## ## If called with only one argument, the poles @var{p} defaults to an empty ## vector, and the denominator coefficient vector @var{a} defaults to 1. ## @end deftypefn ## FIXME: Consider a plot-like interface: ## zplane(x1,y1,fmt1,x2,y2,fmt2,...) ## with y_i or fmt_i optional as usual. This would allow ## legends and control over point color and filters of ## different orders. function zplane(z, p = []) if (nargin < 1 || nargin > 2) print_usage; endif if columns(z)>1 || columns(p)>1 if rows(z)>1 || rows(p)>1 ## matrix form: columns are already zeros/poles else ## z -> b ## p -> a if isempty(z), z=1; endif if isempty(p), p=1; endif M = length(z) - 1; N = length(p) - 1; z = [ roots(z); zeros(N - M, 1) ]; p = [ roots(p); zeros(M - N, 1) ]; endif endif xmin = min([-1; real(z(:)); real(p(:))]); xmax = max([ 1; real(z(:)); real(p(:))]); ymin = min([-1; imag(z(:)); imag(p(:))]); ymax = max([ 1; imag(z(:)); imag(p(:))]); xfluff = max([0.05*(xmax-xmin), (1.05*(ymax-ymin)-(xmax-xmin))/10]); yfluff = max([0.05*(ymax-ymin), (1.05*(xmax-xmin)-(ymax-ymin))/10]); xmin = xmin - xfluff; xmax = xmax + xfluff; ymin = ymin - yfluff; ymax = ymax + yfluff; r = exp (2i * pi * [0:100] / 100); plot (real (r), imag (r), "k"); axis equal; grid on; axis (1.05 * [xmin, xmax, ymin, ymax]); hold on; plot_with_labels (z, "o"); plot_with_labels (p, "x"); hold off; endfunction function plot_with_labels (x, symbol) if (! isempty(x)) colors = get (gca (), "colororder"); for c = 1:columns (x) color = colors(mod (c, rows (colors)), :); plot (real (x(:,c)), imag (x(:,c)), "color", color, ... "linestyle", "none", "marker", symbol); x_u = unique (x(:,c)); for i = 1:length (x_u) n = sum (x_u(i) == x(:,c)); if (n > 1) label = sprintf (" ^%d", n); text (real (x_u(i)), imag (x_u(i)), label, "color", color); endif endfor endfor endif endfunction %!demo %! ## construct target system: %! ## symmetric zero-pole pairs at r*exp(iw),r*exp(-iw) %! ## zero-pole singletons at s %! pw = [0.2, 0.4, 0.45, 0.95]; # pw = [0.4]; %! pr = [0.98, 0.98, 0.98, 0.96]; # pr = [0.85]; %! ps = []; %! zw = [0.3]; # zw=[]; %! zr = [0.95]; # zr=[]; %! zs = []; %! %! ## system function for target system %! p = [[pr, pr] .* exp(1i * pi * [pw, -pw]), ps]'; %! z = [[zr, zr] .* exp(1i * pi * [zw, -zw]), zs]'; %! M = length(z); %! N = length(p); %! sys_a = [zeros(1, M-N), real(poly(p))]; %! sys_b = [zeros(1, N-M), real(poly(z))]; %! %! disp ("The first two graphs should be identical, with poles at (r,w) ="); %! disp (sprintf(" (%.2f,%.2f)", [pr; pw])); %! disp ("and zeros at (r,w) ="); %! disp (sprintf(" (%.2f,%.2f)", [zr; zw])); %! disp ("with reflection across the horizontal axis"); %! %! subplot (2, 3, 1); %! zplane (sys_b, sys_a); %! title ("Transfer function form"); %! %! subplot (2, 3, 2); %! zplane (z, p); %! title ("Zero pole form"); %! %! subplot (2, 3, 3); %! zplane (z); %! title ("Zeros only, p=[]"); %! %! subplot (2, 3, 4); %! zplane (sys_b); %! title ("Numerator only, a=1"); %! %! disp ("The matrix plot has 2 sets of points, one inside the other"); %! subplot (2, 3, 5); %! zplane ([z, 0.7*z], [p, 0.7*p]); %! title ("Matrix of zeros and poles"); signal-1.4.5/io.sourceforge.octave.signal.metainfo.xml0000644000000000000000000000240214456505401021176 0ustar0000000000000000 io.sourceforge.octave.signal org.octave.Octave.desktop Signal Processing Signal processing, measurement, filtering, windowing, and spectral analysis FIR filter IIR filter convolution digital filter linear filter signal measurement signal processing spectral analysis window function https://octave.sourceforge.io/signal/ https://savannah.gnu.org/bugs/?group=octave FSFAP GPL-3.0+ Octave-Forge Community octave-maintainers@gnu.org signal-1.4.5/src/0000755000000000000000000000000014456505401011757 5ustar0000000000000000signal-1.4.5/src/Makefile0000644000000000000000000000307514456505401013424 0ustar0000000000000000# Makefile for the signal package for GNU Octave # # Copyright (C) 2012-2019 Mike Miller # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, see # . MKOCTFILE ?= mkoctfile SED ?= sed PKG_CXXFLAGS := -Wall $(PKG_CXXFLAGS_APPEND) OCT_FILES = \ __fwht__.oct \ __ultrwin__.oct \ cl2bp.oct \ firpm.oct \ medfilt1.oct \ remez.oct \ sosfilt.oct \ upfirdn.oct CL2BP_OBJECTS = cl2bp.o cl2bp_lib.o FIRPM_OBJECTS = firpm.o mmfir.o OCT_SOURCES = $(patsubst %.oct,%.cc,$(OCT_FILES)) all: $(OCT_FILES) %.o: %.cc $(MKOCTFILE) $(PKG_CXXFLAGS) -c $< -o $@ %.o: %.c $(MKOCTFILE) -c $< -o $@ %.oct: %.cc octave-compat.h $(MKOCTFILE) $(PKG_CXXFLAGS) $< -o $@ cl2bp.oct: $(CL2BP_OBJECTS) $(MKOCTFILE) $(PKG_CXXFLAGS) $^ -o $@ firpm.oct: $(FIRPM_OBJECTS) $(MKOCTFILE) $(PKG_CXXFLAGS) $^ -o $@ $(CL2BP_OBJECTS): cl2bp_lib.h octave-compat.h PKG_ADD PKG_DEL: $(OCT_SOURCES) $(SED) -n -e 's/.*$@: \(.*\)/\1/p' $^ > $@-t mv $@-t $@ clean: -rm -f *.o *.oct PKG_* .PHONY: all clean signal-1.4.5/src/__fwht__.cc0000644000000000000000000000331014456505401014027 0ustar0000000000000000/* Copyright (C) 2013-2019 Mike Miller This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, see . */ #include template static void do_fwht (T *x, octave_idx_type n) { double *xa = &x[0]; double *xb = &x[n/2]; // Perform the FWHT butterfly on the input for (octave_idx_type i = 0; i < n/2; i++) { double ya = xa[i] + xb[i]; double yb = xa[i] - xb[i]; xa[i] = ya; xb[i] = yb; } // Divide and conquer if (n > 2) { do_fwht (xa, n/2); do_fwht (xb, n/2); } } DEFUN_DLD (__fwht__, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} __fwht__ (@var{x})\n\ Undocumented internal function.\n\ @end deftypefn") { int nargin = args.length (); if (nargin != 1) print_usage (); else { NDArray x = args(0).array_value (); octave_idx_type n = x.rows (); double *data = x.fortran_vec (); for (octave_idx_type i = 0; i < x.columns (); i++) { do_fwht (&data[i*n], n); } return octave_value (x); } return octave_value (); } /* ## No test needed for internal helper function. %!assert (1) */ signal-1.4.5/src/__ultrwin__.cc0000644000000000000000000002222414456505401014570 0ustar0000000000000000/* Copyright (C) 2013 Rob Sykes This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, see . */ #include #include #include #include #include #if !defined M_PI #define M_PI 3.14159265358979323846 #endif #if defined (__cplusplus) && __cplusplus > 201402L # define ATTR_FALLTHROUGH [[fallthrough]] #elif defined (__GNUC__) && __GNUC__ >= 7 # define ATTR_FALLTHROUGH __attribute__ ((__fallthrough__)) #else # define ATTR_FALLTHROUGH ((void) 0) #endif #if DEBUG_ULTRWIN #define SHOW1(x) fprintf(stderr, "%c%+.3e", " 1"[(x) > .5], (x) - ((x) > .5)) #endif #define EPSILON (1./0x100000) /* For caller rounding error. */ #define BETA_MAX (12*(1+EPSILON)) #define XMU_MIN (.99*(1-EPSILON)) static double * ultraspherical_win(int n, double mu, double xmu) { double * w = NULL; int bad = n < 1 || xmu < XMU_MIN || (!mu && xmu == 1) || (n > BETA_MAX * 2 && xmu * cos(M_PI * BETA_MAX / n) > 1); if (!bad && (w = (double *)malloc(sizeof(*w)* n))) { int i, j, k, l = 0, m = (n + 1) / 2, met; double * divs = w + m - 1, c = 1 - 1 / (xmu * xmu), t, u, v[64], vp, s; for (i = 0; i < (int)(sizeof(v) / sizeof(v[0])); v[i++] = 0); if (n > 1) for (i = 0; i < m; l = j - (j <= i++)) { vp = *v, s = *v = i? (*v + v[1]) * mu * (divs[i] = 1./i) : 1; for (met = 0, j = 1, u = 1; ; ++l, v[l] = vp * (i - l) / (mu + l - 1)) { #define _ t = v[j], v[j] += vp, vp = t, t = s, s += \ v[j] * (u *= c * (n - i - j) * divs[j]), met = s && s == t, ++j, for (k = ((l-j+1) & ~7) + j; j < k && !met; _ _ _ _ _ _ _ _ (void)0); for (; j <= l && !met; _ (void)0); #undef _ if (met || !(j <= i)) break; } w[i] = s / (n - i - 1); } else w[0] = 1; u = 1 / w[i = m - 1], w[i] = 1; for (--i ; i >= 0; u *= (n - 2 - i + mu) / (n - 2 - i), w[i] *= u, --i); for (i = 0; i < m; w[n - 1 - i] = w[i], ++i); } return w; } typedef struct {double f, fp;} uspv_t; static uspv_t ultraspherical_polyval(int n, double mu, double x, double const *divs) { double fp = n > 0? 2 * x * mu : 1, fpp = 1, f; uspv_t result; int i, k; #define _ f = (2*x*(i+mu)*fp - (i+2*mu-1)*fpp) * divs[i+1], fpp=fp, fp=f, ++i, for (i = 1, k = i + ((n - i) & ~7); i < k; _ _ _ _ _ _ _ _ (void)0); for (; i < n; _ (void)0); #undef _ result.f = fp, result.fp = fpp; return result; } #define MU_EPSILON (1./0x4000) #define EQ(mu,x) (fabs((mu)-(x)) < MU_EPSILON) static uspv_t ultraspherical_polyval2( /* With non-+ve integer protection */ int n, double mu, double x, double const * divs) { int sign = (~(int)floor(mu) & ~(~2u/2))? 1:-1; /* -ve if floor(mu) <0 & odd */ uspv_t r; if (mu < MU_EPSILON && EQ(mu,(int)mu)) mu = floor(mu + .5) + MU_EPSILON * ((int)mu > mu? -1:1); r = ultraspherical_polyval(n, mu, x, divs); r.f *= sign, r.fp *= sign; return r; } static double find_zero(int n, double mu, int l, double extremum_mag, double ripple_ratio, double lower_bound, double const *divs) { double dx, x0, t, x, epsilon = 1e-10, one_over_deriv, target = 0; int i, met = 0; if (!divs) return 0; if (!l) { double r = ripple_ratio; /* FIXME: factor in weighted extremum_mag here */ x = r > 1 ? cosh(acosh(r) / n) : cos(acos(r) / n); /* invert chebpoly-1st */ x0 = x *= lower_bound / cos(M_PI * .5 / n) + epsilon; target = log(extremum_mag * ripple_ratio); } else { double cheb1 = cos(M_PI * (l - .5) / n), cheb2 = cos(M_PI * l / (n + 1)); if (mu < 1 - l && EQ((int)(mu+.5),mu+.5)) x = met = 1; else if (EQ(mu,0)) x = cheb1, met = 1; /* chebpoly-1st-kind */ else if (EQ(mu,1)) x = cheb2, met = 1; /* chebpoly-2nd-kind */ else x = (cheb1 * cheb2) / (mu * cheb1 + (1 - mu) * cheb2); x0 = x; } for (i = 0; i < 24 && !met; ++i, met = fabs(dx) < epsilon) {/*Newton-Raphson*/ uspv_t r = ultraspherical_polyval2(n, mu, x, divs); if (!(t = ((2*mu + n-1) * r.fp - n*x * r.f))) /* Fail if div by 0 */ break; one_over_deriv = (1 - x*x) / t; /* N-R slow for deriv~=1, so take log: */ if (!l) { /* d/dx(f(g(x))) = f'(g(x)).g'(x) */ one_over_deriv *= r.f; /* d/dx(log x) = 1/x */ if (r.f <= 0) /* Fail if log of non-+ve */ break; if (x + (dx = (target - log(r.f)) * one_over_deriv) <= lower_bound) dx = (lower_bound - x) * .875; x += dx; } else x += dx = -r.f * one_over_deriv; #if DEBUG_ULTRWIN fprintf(stderr, "1/deriv=%9.2e dx=%9.2e x=", one_over_deriv, dx); SHOW1(x); fprintf(stderr, "\n"); #endif } #if DEBUG_ULTRWIN fprintf(stderr, "find_zero(n=%i mu=%g l=%i target=%g r=%g x0=", n, mu, l, target, ripple_ratio); SHOW1(x0); fprintf(stderr, ") %s ", met? "converged to" : "FAILED at"); SHOW1(x); fprintf(stderr, " in %i iterations\n", i); #else static_cast(x0); #endif return met? x : 0; } static double * make_divs(int n, double **divs) { int i; if (!*divs) { *divs = (double *)malloc(n * sizeof(**divs)); if (*divs) for (i = 0; i < n; (*divs)[i] = 1./(i+1), ++i); } return *divs? *divs - 1 : 0; } #define DIVS make_divs(n, &divs) typedef enum {uswpt_Xmu, uswpt_Beta, uswpt_AttFirst, uswpt_AttLast} uswpt_t; double * ultraspherical_window(int n, double mu, double par, uswpt_t type, int even_norm, double *xmu_) { double * w = 0, xmu = 0, * divs = 0, last_extremum_pos = 0; if (n > 0 && fabs(mu) <= (8*(1+EPSILON))) switch (type) { case uswpt_Beta: xmu = mu == 1 && par == 1? 1 : par < .5 || par > BETA_MAX? 0 : find_zero(n-1, mu, 1, 0, 0, 0, DIVS) / cos(M_PI * par / n); break; case uswpt_AttFirst: if (par < 0) break; ATTR_FALLTHROUGH; case uswpt_AttLast: if (type == uswpt_AttLast && mu >= 0 && par < 0); else if (!EQ(mu,0)) { int extremum_num = type == uswpt_AttLast? (int)((n-2)/2 +.5) : 1 + EQ(mu,-1.5); double extremum_pos = find_zero(n-2, mu+1, extremum_num, 0, 0, 0, DIVS); double extremum_mag = !extremum_pos? 0 : fabs(ultraspherical_polyval2(n-1, mu, extremum_pos, DIVS).f); double xmu_lower_bound = !extremum_mag? 0 : find_zero(n-1, mu, 1, 0, 0, 0, DIVS); /* 1st null */ xmu = !xmu_lower_bound? 0 : find_zero( n-1, mu, 0, extremum_mag, pow(10, par/20), xmu_lower_bound, DIVS); last_extremum_pos = type == uswpt_AttLast? extremum_pos : last_extremum_pos; } else xmu = cosh(acosh(pow(10, par/20))/(n-1)); /* Cheby 1st kind */ break; default: case uswpt_Xmu: xmu = par; break; } #if DEBUG_ULTRWIN fprintf(stderr, "n=%i mu=%.3f xmu=%.16g\n", n, mu, xmu); #endif if (xmu > 0) w = ultraspherical_win(n, mu, xmu); if (w && (~n & !!even_norm) && n > 2 && !(mu == 1 && xmu == 1)) { int i = n / 2 - 1, j = 1; double * d = DIVS, t = 0, s = -1, x = even_norm == 1? 0 : last_extremum_pos? last_extremum_pos : find_zero(n-2, mu+1, i, 0, 0, 0, d); x = x? M_PI/2 - acos(x/xmu) : 0; for (; i >= 0; t += w[i] * d[j] * (s=-s) * (x?cos(j*x):1), --i, j += 2); for (t = M_PI/4 / t, i = 0; t < 1 && i < n; w[i] *= t, ++i); #if DEBUG_ULTRWIN fprintf(stderr, "%snorm DFT(w.sinc Ï€x) @ %g %.16g\n", t<1? "":"NO ", 2*x,t); #endif } free(divs); if (xmu_) *xmu_ = xmu; return w; } //---------------------------------------------------------------------------- DEFUN_DLD (__ultrwin__, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} __ultrwin__ (@var{m}, @var{mu}, @var{par}, @var{par_type}, @var{norm})\n\ Undocumented internal function.\n\ @end deftypefn") { octave_value_list retval; int nargin = args.length (); if (nargin != 5) { print_usage (); return retval; } for (octave_idx_type i = 0; i < nargin; i++) if (! args(i).is_real_scalar ()) { print_usage (); return retval; } int m = args(0).scalar_value (); double mu = args(1).scalar_value (); double par = args(2).scalar_value (); uswpt_t par_type = static_cast (args(3).scalar_value ()); int even_norm = args(4).scalar_value (); double xmu; double *w = ultraspherical_window (m, mu, par, par_type, even_norm, &xmu); if (!w) { error ("ultrwin: parameter(s) out of range"); return retval; } ColumnVector ww (m); for (octave_idx_type i = 0; i < m; i++) ww(i) = w[i]; free (w); retval(0) = ww; retval(1) = xmu; return retval; } /* ## No test needed for internal helper function. %!assert (1) */ signal-1.4.5/src/cl2bp.cc0000644000000000000000000001041614456505401013272 0ustar0000000000000000/* Copyright (C) 2008-2009 Evgeni A. Nurminski Copyright (C) 2008-2009 Pete Gonzalez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, see . */ #include #include "cl2bp_lib.h" #include "octave-compat.h" static void cancel_handler(void *) { OCTAVE_QUIT; } // When CL2BP_LOGGING is defined, this will direct messages to the Octave pager void cl2bp_log(const char *message) { octave_stdout << message; } DEFUN_DLD (cl2bp, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{h} =} cl2bp (@var{m}, @var{w1}, @var{w2}, @var{up}, @var{lo})\n\ @deftypefnx {Loadable Function} {@var{h} =} cl2bp (@var{m}, @var{w1}, @var{w2}, @var{up}, @var{lo}, @var{gridsize})\n\ \n\ Constrained L2 bandpass FIR filter design. This is a fast implementation of\n\ the algorithm cited below. Compared to @dfn{remez}, it offers implicit\n\ specification of transition bands, a higher likelihood of convergence, and an\n\ error criterion combining features of both L2 and Chebyshev approaches.\n\ \n\ Inputs:\n\ \n\ @table @var\n\ @item m\n\ degree of cosine polynomial, i.e. the number of output coefficients will be\n\ @var{m}*2+1\n\ @item w1\n\ @itemx w2\n\ bandpass filter cutoffs in the range 0 <= @var{w1} < @var{w2} <= pi,\n\ where pi is the Nyquist frequency\n\ @item up\n\ vector of 3 upper bounds for [stopband1, passband, stopband2]\n\ @item lo\n\ vector of 3 lower bounds for [stopband1, passband, stopband2]\n\ @item gridsize\n\ search grid size; larger values may improve accuracy,\n\ but greatly increase calculation time.\n\ @end table\n\ \n\ Output:\n\ \n\ A vector of @var{m}*2+1 FIR coefficients, or an empty value if the solver\n\ failed to converge.\n\ \n\ Example:\n\ @example\n\ @code{h = cl2bp(30, 0.3*pi, 0.6*pi, [0.02, 1.02, 0.02], [-0.02, 0.98, -0.02], 2^11);}\n\ @end example\n\ \n\ Original Paper: I. W. Selesnick, M. Lang, and C. S. Burrus. A modified\n\ algorithm for constrained least square design of multiband FIR filters without\n\ specified transition bands.\n\ IEEE Trans. on Signal Processing, 46(2):497-501, February 1998.\n\ @end deftypefn\n\ @seealso{remez}\n") { octave_value_list retval; const int nargin = args.length(); if (nargin < 5 || nargin > 6) { print_usage (); return retval; } const int m = args(0).int_value(true); const double w1 = args(1).double_value(); const double w2 = args(2).double_value(); const ColumnVector up_vector(args(3).vector_value()); const ColumnVector lo_vector(args(4).vector_value()); if (up_vector.numel() != 3 || lo_vector.numel() != 3) { error("cl2bp: The up and lo vectors must contain 3 values"); return retval; } double up[3]; double lo[3]; for (int i=0; i<3; ++i) { up[i] = up_vector(i); lo[i] = lo_vector(i); } const int L = args(5).int_value(true); if (L > 1000000) { error("cl2bp: The \"gridsize\" parameter cannot exceed 1000000"); return retval; } MallocArray h; try { cl2bp(h, m, w1, w2, up, lo, L, 1.e-5, 20, cancel_handler); } catch (std::exception &ex) { error("%s", ex.what()); return retval; } ColumnVector h_vector(h.get_length()); for (int i=0; i Copyright (C) 2008-2009 Pete Gonzalez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, see . */ #ifdef _MSC_VER #define _CRT_SECURE_NO_WARNINGS // disable spurious warnings #define _USE_MATH_DEFINES // for math.h #endif #include "cl2bp_lib.h" #include #include #include #include #include #include #define BIG_NUMBER 100000 //----------------------------------------------------------------------------------------------------------- #ifdef CL2BP_LOGGING static void log_printf(const char *format, ...) { va_list argptr; va_start(argptr, format); char buf[20*1024]; if (vsnprintf(buf,20*1024-1,format,argptr) == -1) { strcpy(buf, "#ERROR#"); } va_end(argptr); cl2bp_log(buf); } #else #define log_printf(...) ((void)0) // don't log anything (for a big speed improvement) #endif //----------------------------------------------------------------------------------------------------------- static int local_max(const MallocArray& x, int n, MallocArray& ix) { int i, mx; mx = 0; MallocArray xx(n+2); xx[0] = xx[n + 1] = -BIG_NUMBER; for ( i = 1; i <= n; i++) xx[i] = x[i - 1]; for ( i = 0; i < n; i++ ) { (((xx[i] < xx[i + 1]) && (xx[i + 1] > xx[i + 2])) || ((xx[i] < xx[i + 1]) && (xx[i + 1] >= xx[i + 2])) || ((xx[i] <= xx[i + 1]) && (xx[i + 1] > xx[i + 2])) ) && ( ix[mx++] = i ); } return mx; } //----------------------------------------------------------------------------------------------------------- static int solvps(MallocArray& a, MallocArray& b, int n, void (*cancel_handler)(void *), void *cancel_state) { double t; int j, k; int a_p; int a_q; int a_r; int a_s; // In empirical tests, 2% to 6% of the execution time was spent in solvps() if (cancel_handler) cancel_handler(cancel_state); for (j = 0, a_p = 0; j < n; ++j, a_p += n+1) { for (a_q = j*n; a_q < a_p; ++a_q) a[a_p] -= a[a_q] * a[a_q]; if (a[a_p] <= 0.) return -1; a[a_p] = sqrt(a[a_p]); for (k = j + 1, a_q = a_p + n; k < n; ++k, a_q += n) { for (a_r = j*n, a_s = k*n, t = 0.; a_r < a_p;) t += a[a_r++] * a[a_s++]; a[a_q] -= t; a[a_q] /= a[a_p]; } } for (j = 0, a_p = 0; j < n; ++j, a_p += n+1) { for (k = 0, a_q = j*n; k < j;) b[j] -=b [k++] * a[a_q++]; b[j] /= a[a_p]; } for (j = n - 1, a_p = n*n - 1; j >= 0; --j, a_p -= n + 1) { for (k = j + 1, a_q = a_p + n; k < n; a_q += n) b[j] -= b[k++]* a[a_q]; b[j] /= a[a_p]; } return 0; } //----------------------------------------------------------------------------------------------------------- static void rmmult(MallocArray& rm, const MallocArray& a, const MallocArray& b, int n, int m, int l, void (*cancel_handler)(void *), void *cancel_state) { double z; int i,j,k; int b_p; // index into b int a_p; // index into a int rm_start = 0; // index into rm int rm_q; // index into rm MallocArray q0(m); for (i = 0; i < l ; ++i, ++rm_start) { // In empirical tests, 87% to 95% of the execution time was spent in rmmult() if (cancel_handler) cancel_handler(cancel_state); for (k = 0, b_p = i; k < m; b_p += l) q0[k++] = b[b_p]; for (j = 0, a_p = 0, rm_q = rm_start; j < n; ++j, rm_q += l) { for (k = 0, z = 0.; k < m;) z += a[a_p++] * q0[k++]; rm[rm_q]=z; } } } //----------------------------------------------------------------------------------------------------------- static void mattr(MallocArray& a, const MallocArray& b, int m, int n) { int i, j; int b_p; int a_p = 0; int b_start = 0; for (i = 0; i < n; ++i, ++b_start) for ( j = 0, b_p = b_start; j < m; ++j, b_p += n ) a[a_p++] = b[b_p]; } //----------------------------------------------------------------------------------------------------------- static void calcAx(MallocArray& Ax, int m, int L) { double r = M_SQRT2, pi = M_PI; int i, j; Ax.resize((L+1)*(m + 1)); for ( i = 0; i <= L; i++) for ( j = 0; j <= m; j++) Ax[i*(m+1) + j] = cos(i*j*pi/L); for ( i = 0; i < (L+1)*(m+1); i += m + 1 ) Ax[i] /= r; } //----------------------------------------------------------------------------------------------------------- #ifdef CL2BP_LOGGING static double L2error(const MallocArray& x, const MallocArray& w, int L, double w1, double w2) { double xx, ww, sumerr, pi = M_PI; int i; for ( i = 0, sumerr = 0; i < L + 1; i++ ) { ww = w[i]; xx = x[i]; sumerr += ( ww < w1*pi || ww > w2*pi ) ? xx*xx : (1 - xx)*(1 - xx); } return sumerr; } #endif // CL2BP_LOGGING //----------------------------------------------------------------------------------------------------------- static double CHerror(double *wmin, const MallocArray& x, const MallocArray& w, int L, double w1, double w2) { double xx, ww, err, errmax; int i; errmax = -1; *wmin = 0; for ( i = 0; i < L + 1; i++ ) { ww = w[i]; xx = x[i]; err = (( ww < w1 ) || (ww > w2 )) ? fabs(xx) : fabs(1 - xx); if ( err > errmax ) { errmax = err; *wmin = ww; } } return errmax; } //----------------------------------------------------------------------------------------------------------- static void Ggen(MallocArray& G, int m, const MallocArray& w, const MallocArray& kmax, int l_kmax, const MallocArray& kmin, int l_kmin) { G.resize((l_kmax + l_kmin)*(m + 1)); int nsys, i, j; double r = M_SQRT2; nsys = l_kmax + l_kmin; for ( i = 0; i < l_kmax; i++) for ( j = 0; j <= m; j++) G[i*(m+1) + j] = cos(w[kmax[i]]*j); for ( i = l_kmax; i < nsys; i++) for ( j = 0; j <= m; j++) G[i*(m+1) + j] = -cos(w[kmin[i - l_kmax]]*j); for ( i = 0; i < nsys*(m+1); i += m+1 ) G[i] /= r; } //----------------------------------------------------------------------------------------------------------- bool cl2bp(MallocArray& h, int m, double w1, double w2, double up[3], double lo[3], int L, double eps, int mit, void (*cancel_handler)(void *), void *cancel_state) { // Ensure sane values for input parameters if (m < 2 || m > 5000) throw std::invalid_argument("cl2bp: The m count must be between 2 and 5000"); if (w1 < 0 || w1 > w2 || w2 > 2*M_PI) throw std::invalid_argument("cl2bp: The cutoffs must be in the range 0 < w1 < w2 < 2*pi"); // Z is allocated as Z(2*L-1-2*m) if (L <= m) throw std::invalid_argument("cl2bp: The \"gridsize\" parameter must be larger than \"m\""); double r = M_SQRT2; double pi = M_PI; double wmin, ww, xw; int q1, q2, q3, i, iter = 0; int off, neg; int ik; int l_kmax; int l_kmin; int l_okmax; int l_okmin; double uvo = 0, lvo = 0; double err, diff_up, diff_lo; double erru, erro; int iup, ilo; int nsys, j; int imin = BIG_NUMBER; double umin; int k1 = -1, k2 = -1, ak1, ak2; double cerr; h.resize(2*m+1); bool converged = true; MallocArray x0(L+1); MallocArray x1(L+1); MallocArray xx(L+1); MallocArray xm1(L+1); MallocArray w(L+1); MallocArray u(L+1); MallocArray l(L+1); MallocArray a(L+1); MallocArray c(L+1); MallocArray kmax(L+1); MallocArray kmin(L+1); l_kmax = l_kmin = 0; MallocArray okmin(L+1); MallocArray okmax(L+1); l_okmax = l_okmin = 0; MallocArray rhs(m+2); MallocArray mu(2*(L+1)); for ( i = 0; i <= L; i++ ) w[i] = i*pi/L; MallocArray Z(2*L-1-2*m); q1 = (int)floor(L*w1/pi); q2 = (int)floor(L*(w2-w1)/pi); q3 = L + 1 - q1 - q2; off = 0; for ( i = 0; i < q1; i++) { u[i] = up[0]; l[i] = lo[0]; } off += i; for ( i = 0; i < q2; i++) { u[off + i] = up[1]; l[off + i] = lo[1]; } off += i; for ( i = 0; i < q3; i++) { u[off + i] = up[2]; l[off + i] = lo[2]; } c[0] = (w2-w1)*r; for ( i = 1; i <= m; i++) c[i] = 2*(sin(w2*i)-sin(w1*i))/i; for ( i = 0; i <= m; i++) { c[i] /= pi; a[i] = c[i]; } log_printf("\nInitial approximation. Unconstrained L2 filter coefficients.\n"); log_printf("=============================================================\n"); log_printf("\nZero order term %8.3lf\n", a[0]); for ( i = 1; i <= m; i++) { log_printf("%4d %8.3lf", i, a[i]); if (i - 8*(i/8) == 0) log_printf("\n"); } log_printf("\n"); // Precalculate Ax MallocArray Ax; calcAx(Ax, m, L); //calcA(x0, a, m, L); rmmult(x0, Ax, a, L + 1, m + 1, 1, cancel_handler, cancel_state); err = CHerror(&wmin, x0, w, L, w1, w2); log_printf("\nChebyshev err %12.4e (%11.5e) <> L2 err %12.4e\n", err, wmin/pi, L2error(x0, w, L, w1, w2)/(L+1)); for (iter = 1; ; iter++) { log_printf("\n:::::: Iteration %3d :::::::::::\n", iter); if ( (uvo > eps*2) || (lvo > eps*2) ) { log_printf("\nXXX Take care of old errors: uvo lvo %12.3e %12.3e", uvo, lvo); if( k1 >= 0 ) log_printf(" k1 %3d(%d)", k1, okmax[k1]); if( k2 >= 0 ) log_printf(" k2 %3d(%d)", k2, okmin[k2]); log_printf("\n"); if ( uvo > lvo ) { kmax[l_kmax] = okmax[k1]; l_kmax++; l_okmax--; for (i = k1; i < l_okmax; i++) okmax[i] = okmax[i + 1]; } else { kmin[l_kmin] = okmin[k2]; l_kmin++; l_okmin--; for (i = k2; i < l_okmin; i++) okmin[i] = okmin[i + 1]; } nsys = l_kmax + l_kmin; /* for (i = 0; i < l_kmax; i++) log_printf("i %3d kmax %3d mu %12.4e\n", i, kmax[i], mu[i]); log_printf("\n"); for (i = 0; i < l_kmin; i++) log_printf("i %3d kmin %3d mu %12.4e\n", i, kmin[i], mu[i + l_kmax]); log_printf("\n\n"); */ } else { //calcA(x1, a, m, L); rmmult(x1, Ax, a, L + 1, m + 1, 1, cancel_handler, cancel_state); for ( i = 0; i < l_kmax; i++) okmax[i] = kmax[i]; for ( i = 0; i < l_kmin; i++) okmin[i] = kmin[i]; l_okmax = l_kmax; l_okmin = l_kmin; l_kmax = local_max(x1, L + 1, kmax); for ( i = 0; i < L + 1; i++) xm1[i] = -x1[i]; l_kmin = local_max(xm1, L + 1, kmin); log_printf("\nSignificant deviations from the ideal filter. Levels:"); log_printf(" %8.2e %8.2e %8.2e (lo)", lo[0], lo[1], lo[2]); log_printf(" %8.2e %8.2e %8.2e (up)", up[0], up[1], up[2]); log_printf("\n"); for ( i = 0, ik = 0; i < l_kmax; i++) { j = kmax[i]; if ( x1[j] > u[j] - 10*eps ) { kmax[ik] = j; ik++; } } l_kmax = ik; log_printf("overshoots = %d\n", l_kmax); for ( i = 0; i < l_kmax; i++) { j = kmax[i]; ww = w[j]; xw = x1[j]; err = (w1 < ww && ww < w2) ? xw - 1 : xw; log_printf(" i = %3d kmax = %3d xw = %12.5e err = %10.3e u = %12.4e max = %9.2e\n", i, j, xw, err, u[j], xw - u[j]); } for ( i = 0, ik = 0; i < l_kmin; i++) { j = kmin[i]; if ( x1[j] < l[j] + 10*eps ) { kmin[ik] = j; ik++; } } l_kmin = ik; log_printf("undershoots = %d\n", l_kmin); for ( i = 0; i < l_kmin; i++) { j = kmin[i]; ww = w[j]; xw = -xm1[j]; err =(w1 < ww && ww < w2) ? xw - 1 : xw; log_printf(" i = %3d kmin = %3d xw = %12.5e err = %10.3e l = %12.4e min = %9.2e\n", i, j, xw, err, l[j], xw - l[j]); } err = erru = erro = diff_up = diff_lo = 0; iup = ilo = 0; for ( i = 0; i < l_kmax; i++) { ik = kmax[i]; diff_up = x1[ik] - u[ik]; if ( diff_up > erru ) { erru = diff_up; iup = i; } } for ( i = 0; i < l_kmin; i++) { ik = kmin[i]; diff_lo = l[ik] - x1[ik]; if ( diff_lo > erro ) { erro = diff_lo; ilo = i; } } err = erro > erru ? erro : erru; log_printf("erru = %14.6e iup = %4d kmax = %4d ", erru, iup, kmax[iup]); log_printf("erro = %14.6e ilo = %4d kmin = %4d\n", erro, ilo, kmin[ilo]); #ifndef CL2BP_LOGGING static_cast(iup); #endif if ( err < eps ) break; } nsys = l_kmax + l_kmin; MallocArray G(nsys*(m + 1)); MallocArray GT(nsys*(m + 1)); MallocArray GG(nsys*nsys); for ( i = 0; i < l_kmax; i++) for ( j = 0; j <= m; j++) G[i*(m+1) + j] = cos(w[kmax[i]]*j); for ( i = l_kmax; i < nsys; i++) for ( j = 0; j <= m; j++) G[i*(m+1) + j] = -cos(w[kmin[i - l_kmax]]*j); for ( i = 0; i < nsys*(m+1); i += m+1 ) G[i] /= r; mattr(GT, G, nsys, m + 1); rmmult(GG, G, GT, nsys, m + 1, nsys, cancel_handler, cancel_state); rmmult(rhs, G, c, nsys, m + 1, 1, cancel_handler, cancel_state); for ( i = 0; i < nsys; i++) if ( i < l_kmax ) rhs[i] -= u[kmax[i]]; else rhs[i] += l[kmin[i - l_kmax]]; for ( i = 0; i < nsys; ++i) mu[i] = rhs[i]; solvps(GG, mu, nsys, cancel_handler, cancel_state); log_printf("\nXXX KT-system with %d equations resolved.\n", nsys); for ( i = 0, neg = 0; i < nsys; i++) if ( mu[i] < 0 ) neg++; log_printf("\nTotal number of negative multipliers = %3d\n\n", neg); while (neg) { umin = BIG_NUMBER; for ( i = 0, j = 0; i < nsys; i++) { if ( mu[i] >= 0 ) continue; j++; if ( mu[i] < umin ) { imin = i; umin = mu[i]; } } if ( umin > 0 ) break; log_printf(" neg = %3d of %3d imin = %3d mu-min = %12.4e\n", j, nsys, imin, umin); for ( i = imin; i < nsys - 1; i++) { rhs[i] = rhs[i + 1]; for ( j = 0; j <= m; j++) G[i*(m + 1) + j] = G[(i + 1)*(m + 1) + j]; } if ( imin < l_kmax ) { for ( i = imin; i < l_kmax - 1; i++) kmax[i] = kmax[i + 1]; l_kmax--; } else { for ( i = imin; i < nsys - 1; i++) kmin[i - l_kmax] = kmin[i - l_kmax + 1]; l_kmin--; } --nsys; mattr(GT, G, nsys, m + 1); rmmult(GG, G, GT, nsys, m + 1, nsys, cancel_handler, cancel_state); for ( i = 0; i < nsys; ++i) mu[i] = rhs[i]; solvps(GG, mu, nsys, cancel_handler, cancel_state); } MallocArray da(m + 1); MallocArray zd(nsys); rmmult(da, GT, mu, m + 1, nsys, 1, cancel_handler, cancel_state); for ( i = 0; i <= m; i++) a[i] = c[i] - da[i]; rmmult(zd, G, a, nsys, m + 1, 1, cancel_handler, cancel_state); MallocArray zz(l_okmax + l_okmin); Ggen(G, m, w, okmax, l_okmax, okmin, l_okmin); rmmult(zz, G, a, l_okmax + l_okmin, m + 1, 1, cancel_handler, cancel_state); uvo = lvo = eps; k1 = k2 = -1; ak1 = ak2 = -1; if (l_okmax + l_okmin > 0) log_printf("\nErrors on the previous set of freqs\n\n"); for (i = 0; i < l_okmax; i++) { j = okmax[i]; cerr = zz[i] - u[j]; log_printf(" i %2d j %3d u %12.4e Ga %12.4e cerr %12.4e\n", i, j, u[j], zz[i], cerr); if ( cerr > uvo ) { uvo = cerr; k1 = i; ak1 = j; } } cerr = 0; for (i = 0; i < l_okmin; i++) { j = okmin[i]; cerr = l[j] + zz[i + l_okmax]; log_printf(" i %2d j %3d l %12.4e Ga %12.4e cerr %12.4e\n", i, j, l[j], zz[i + l_okmax], cerr); if ( cerr > lvo ) { lvo = cerr; k2 = i, ak2 = j; } } if ( l_okmax + l_okmin > 0 ) { log_printf("\n uvo = %12.4e k1 = %4d (%3d) ", uvo, k1, ak1); log_printf(" lvo = %12.4e k2 = %4d (%3d) ", lvo, k2, ak2); log_printf(" maxerr = %12.4e\n", uvo > lvo ? uvo : lvo); #ifndef CL2BP_LOGGING static_cast(ak1); #endif } log_printf("\nConstrained L2 band filter coefficients.\n"); log_printf("=====================================\n"); #ifdef CL2BP_LOGGING log_printf("\nZero order term %8.3lf\n", a[0]); for ( i = 1; i <= m; i++) { log_printf("%4d %8.3lf", i, a[i]); if (i - 8*(i/8) == 0) log_printf("\n"); } log_printf("\n"); #endif //calcA(xx, a, m, L); rmmult(xx, Ax, a, L + 1, m + 1, 1, cancel_handler, cancel_state); if ( iter >= mit ) { log_printf("Maximum iterations reached\n"); converged = false; } } for (i = 0; i < m; i++) { h[i] = a[m - i]/2; h[m + i + 1] = a[i + 1]/2; } h[m] = a[0]*r/2; return converged; } signal-1.4.5/src/cl2bp_lib.h0000644000000000000000000000731514456505401013766 0ustar0000000000000000/* Copyright (C) 2008-2009 Evgeni A. Nurminski Copyright (C) 2008-2009 Pete Gonzalez This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, see . */ #ifndef CL2BP_H #define CL2BP_H #include #include #include //for memset //----------------------------------------------------------------------------------------------------------- // If you want to debug the cl2bp algorithm, define the CL2BP_LOGGING symbol and provide an // implementation of cl2bp_log(). #ifdef CL2BP_LOGGING extern void cl2bp_log(const char *message); #endif //----------------------------------------------------------------------------------------------------------- // This is a simple helper class that performs bounds-checking for debug builds, but reduces to an unchecked // malloc() array for release builds. template class MallocArray { int length; T *ptr; public: T& operator[](int index) { assert(index >= 0 && index < length); return ptr[index]; } T operator[](int index) const { assert(index >= 0 && index < length); return ptr[index]; } int get_length() const { return length; } void resize(int length_) { assert(length_ >= 0 && length_ <= 512*1024*1024); // verify that the array size is reasonable length = length_; ptr = (T *)realloc(ptr, length * sizeof(T)); std::memset(ptr, 0, length * sizeof(T)); } MallocArray(int length_=0) { ptr = 0; length = 0; if (length_) resize(length_); } ~MallocArray() { free(ptr); } private: MallocArray(const MallocArray&) { } // copy constructor is unimplemented and disallowed }; //----------------------------------------------------------------------------------------------------------- // Constrained L2 BandPass FIR filter design // h 2*m+1 filter coefficients (output) // m degree of cosine polynomial // w1,w2 fist and second band edges // up upper bounds // lo lower bounds // L grid size // eps stopping condition ("SN") // mit maximum number of iterations // // cl2bp() returns true if the solver converged, or false if the maximum number of iterations was reached. // If provided, the cancel_handler function pointer will be called periodically inside long-running loops, // giving an opportunity to abort (by throwing a C++ exception). The cancel_state parameter is a // user-defined pointer, e.g. a button object, boolean flag, or other means of detecting a cancel request. // // Example usage: // MallocArray coefficients; // double up[3] = { 0.02, 1.02, 0.02 }; // double lo[3] = { -0.02, 0.98, -0.02 }; // cl2bp(coefficients, 30, 0.3*M_PI, 0.6*M_PI, up, lo, 1<<11, 1.e-5, 20); // // The algorithm is described in this paper: // I. W. Selesnick, M. Lang, and C. S. Burrus. A modified algorithm for constrained least square // design of multiband FIR filters without specified transition bands. IEEE Trans. on Signal // Processing, 46(2):497-501, February 1998. bool cl2bp(MallocArray& h, int m, double w1, double w2, double up[3], double lo[3], int L, double eps, int mit, void (*cancel_handler)(void *)=0, void *cancel_state=0); #endif signal-1.4.5/src/firpm.cc0000644000000000000000000011134114456505401013404 0ustar0000000000000000//////////////////////////////////////////////////////////////////////// // // Copyright (C) 2014/15/21 Rob Sykes // // See the file COPYRIGHT.md in the top-level directory of this // distribution or . // // This file is part of Octave. // // Octave is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Octave is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Octave; see the file COPYING. If not, see // . // //////////////////////////////////////////////////////////////////////// #include "mmfir.h" #include #include #include #include #include #include "octave-compat.h" #define AL(x) (int)(sizeof (x)/sizeof (x[0])) // Array-Length #define returnError(...) do { error (__VA_ARGS__);\ return octave_value_list (); } while (0) enum { RESP_FN_ARG_N, RESP_FN_ARG_F, RESP_FN_ARG_G, RESP_FN_ARG_W, RESP_FN_ARG_VAR }; static MmfirResult mmfirRespFn (MmfirBandSpec const * bandSpecs, int len, MmfirPoint points[], va_list args) { (void)bandSpecs; octave_fcn_handle * const respFnHandle(va_arg (args, octave_fcn_handle *)); octave_value_list * const respFnArgs (va_arg (args, octave_value_list *)); ColumnVector G (len); for (int i=0; ifunction_value (), *respFnArgs, 2)); auto const nargout (result.length ()); ColumnVector A; if (nargout>0) A=result (0).vector_value (); ColumnVector W; if (nargout>1) W=result (1).vector_value (); if (A.numel ()!=len) { error ("firpm respFn amplitude length %i should be %i", (int)A.numel (), len); return MmfirInvalidAmplitude; } if (W.numel ()!=len && nargout>1) { error ("firpm respFn weight length %i should be %i", (int)W.numel (), len); return MmfirInvalidWeight; } if (nargout>1) for (int i=0; i=f(3))*9+1));\n\ @end group\n\ @end example\n\ \n\ @example\n\ @group\n\ # Band-pass with filter-response check:\n\ freqz (firpm (40, [0 3 4 6 8 10]/10, [0 1 0]))\n\ @end group\n\ @end example\n\ \n\ Further examples can be found in the @code{firpm} and @code{firpmord}\n\ demonstration scripts.\n\ \n\ @heading Compatibility\n\ Given invalid filter specifications, Octave emits an error and does not produce\n\ a filter; @sc{matlab} in such circumstances may still produce filter\n\ coefficients.\n\ \n\ Unlike with @sc{matlab}, with Octave @var{minimax} can be negative; for\n\ compatibility, take the absolute value.\n\ \n\ @xseealso{firpmord}\n\ \n\ @end deftypefn\n\ ") { int i, arg (0), nargin((int)args.length ()), N; octave_value_list respFnArgs; // The first 3 parameters are mandatory: if (nargin < 3) { print_usage (); return octave_value_list (); } // N: octave_value const & v = args(arg++); if (!v.is_real_scalar () || (N = (int)v.scalar_value ()) != v.scalar_value ()) returnError ("firpm parameter N (filter order) must be an integer"); respFnArgs (RESP_FN_ARG_N) = v; // F[]: ColumnVector freqs; if (!args(arg).is_string () && args(arg).is_real_matrix ()) freqs = args(arg++).vector_value (); if (freqs.numel () < 2 || (freqs.numel () & 1)) returnError ("firpm parameter F (band-edge frequencies) " "must be a real, even-lengthed vector"); int numBands((int)freqs.numel () >> 1); OCTAVE_LOCAL_BUFFER (MmfirBandSpec, bands, numBands); for (i = 0; i < numBands; ++i) bands[i].freqL = freqs(2*i), bands[i].freqR = freqs(2*i+1); respFnArgs (RESP_FN_ARG_F) = freqs; respFnArgs (RESP_FN_ARG_G) = ColumnVector(); // Overwritten later. respFnArgs (RESP_FN_ARG_W) = ColumnVector(numBands, 1); // ditto // @RESP_FN or A[]: octave_fcn_handle * respFnHandle(0); if (args(arg).is_function_handle()) respFnHandle = args(arg++).fcn_handle_value (); else if (octave::signal::iscell(args(arg))) { Cell c(args(arg).cell_value ()); int k(0); if (c.numel () >= 1 && c(k).is_function_handle ()) { respFnHandle = c(k++).fcn_handle_value (); for (; k>= 1; // Shift away alternative names. } if (Class<0 && respFnHandle && !respFnHandle->function_value ()->is_anonymous_function ()) { octave_value_list args; args(0) = respFnHandle->fcn_name (); args(1) = Cell(respFnArgs); octave_value_list result(octave::feval ("__firpm_probe__", args, 1)); Class = std::min ((int)result(0).scalar_value (), 2); // For safety. } Class=std::max (Class, 0); // Default is 'symmetric'. // PROPERTIES: static char const * const propertyNames[] = { "ACCURACY", "PERSISTENCE", "ROBUSTNESS", "TARGET", "FLAGS" }; double realProperties[] = { 0, 0, 0, 0, 0 }; if (arg < nargin && octave::signal::iscell(args(arg)) ) { Cell c(args(arg).cell_value ()); if (c.numel ()) { for (i=0; i2? &state : 0, respFnHandle? mmfirRespFn:0, respFnHandle, &respFnArgs)); // Warn if any controls were clamped: for (i = 0; i < AL(report.controls); ++i) if (report.controls[i] != realProperties[i]) warning ("firpm property %s was clamped to %g", propertyNames[i], report.controls[i]); // Check if a filter was generated: if (report.result >= MmfirInvocationError) returnError ("firpm invocation error: %s", report.text); else if (report.result >= MmfirError) returnError ("firpm failed to make a filter (result=%i)", report.result); // Missed-target is handled silently: if (report.result == MmfirMissedTarget) N = -1; // Return empty B. else // Check if a warning should be issued: if (report.result >= MmfirWarning) warning ("firpm %s (result=%i)", report.text, report.result); // Copy filter coefficients to an Octave row-vector: RowVector b(N+1); for (int i=N+1; i--;) b(i) = h[i]; // Return [B, MINIMAX, RES]: octave_value_list ret; ret(0) = octave_value(b); if (nargout>1) // MINIMAX: ret(1) = octave_value(report.minimax * (report.result? -1 : +1)); if (nargout>2) // RES: { int const S(state.spaceLength); int const P(state.peaksLength); ColumnVector fgrid(S), FP(S), des(S), wt(S), err(S); ColumnVector iextr(P), fextr(P); ComplexColumnVector H(S); double const mulA(Class==2? -1:1); double const mulW(Class==2? .5:1); for (int i=0; i firpm (1.1, 2, 3); %!error firpm (i, 2, 3); %!error firpm ([1 2], 2, 3); %!error firpm (1, 2, 3); %!error firpm (2, [1 2 3], 3); %!error firpm (2, [1 i], 3); %!error firpm (1, [1 2], i); %!error firpm (1, [1 2], []); %!error firpm (1, [1 2], [1 2 3]); %!error firpm (1, [1 2], [1 i]); %!error firpm (1, [1 2], 1, []); %!error firpm (1, [1 2], 1, [1 2 3]); %!error firpm (1, [1 2], 1, [1 2], 'diffi'); %!error firpm (1, [1 2], 1, [1 2], 'hilberts'); %!error firpm (1, [1 2], 1, [1 2], {'antisymmetric'}); %!error firpm (1, [1 2], 1, [1 2], {0, [1 1]}); %!error firpm (1, [1 2], 1, i); %!error firpm (2, [0 1], [1 0], {}, 1); %!warning firpm (1, [.1 .9], 1, [1 2], {0,0,-1}); %!error firpm (2, [.1 .9], 1); %!error firpm (1, [1 2], 1, [1 2], 'diff'); %!error firpm (81, [0 .2 .3 1], [1 -1]); %!error firpm (81, [0 .2 .3 1], [-1 0], 'a'); Functional tests The first 6 tests exercise all 6 filter type (3 classes, odd/even-order). The b0 values come from a reference implementation. %!test b0 = [ %! -0.01306844322361 %! -0.00576879446491 %! 0.00838126690529 %! -0.04580777271297 %! -0.03857170268345 %! -0.06564404551953 %! -0.03895798206108 %! 0.10957536253443 %! -0.09596565600341 %! -0.04596208116089 %! 0.25250866248593 %! -0.04596208116089 %! -0.09596565600341 %! 0.10957536253443 %! -0.03895798206108 %! -0.06564404551953 %! -0.03857170268345 %! -0.04580777271297 %! 0.00838126690529 %! -0.00576879446491 %! -0.01306844322361 %! ]'; %! [b m] = firpm (20, [0 .2 .3 .4 .5 .7 .9 1], [0 .2 0 0 .5 .7 0 0], [1 4 16 64], 'b', {256}); %! assert (b0, b, 1e-5); assert (m, 0.21493, -5e-5); %!test b0 = [ %! -0.00025230206347 %! -0.01634334994986 %! 0.02291167335102 %! 0.04226921430992 %! 0.01542390317553 %! 0.03368560169380 %! -0.07263229297607 %! 0.02402776579442 %! 0.10971999889298 %! -0.19495185723437 %! 0 %! 0.19495185723437 %! -0.10971999889298 %! -0.02402776579442 %! 0.07263229297607 %! -0.03368560169380 %! -0.01542390317553 %! -0.04226921430992 %! -0.02291167335102 %! 0.01634334994986 %! 0.00025230206347 %! ]'; %! [b m] = firpm (20, [0 .2 .3 .4 .5 .7 .9 1], [0 .2 0 0 .5 .7 0 0], [1 4 16 64], 'h', {256}); %! assert (b0, b, 1e-5); assert (m, 0.19499, -5e-5); %!test b0 = [ %! -0.00377491711564 %! 0.00749876297245 %! -0.01857378491500 %! -0.02436623414958 %! 0.02123220611895 %! -0.00133887288041 %! 0.08769905297256 %! -0.01438000909341 %! -0.11006930405280 %! 0.20125570410204 %! 0 %! -0.20125570410204 %! 0.11006930405280 %! 0.01438000909341 %! -0.08769905297256 %! 0.00133887288041 %! -0.02123220611895 %! 0.02436623414958 %! 0.01857378491500 %! -0.00749876297245 %! 0.00377491711564 %! ]'; %! [b m] = firpm (20, [0 .2 .3 .4 .5 .7 .9 1], [0 .2 0 0 .5 .7 0 0], [1 4 16 64], 'd', {256}); %! assert (b0, b, 1e-5); assert (m, 0.49129, -5e-5); %!test b0 = [ %! 0.00110112420442 %! 0.00032786748236 %! 0.03890416611405 %! 0.02776952210339 %! -0.00513106293312 %! 0.00821219616448 %! -0.05050622257469 %! 0.07143158068636 %! 0.04353182141693 %! -0.17253512167493 %! 0.13296924791431 %! 0.13296924791431 %! -0.17253512167493 %! 0.04353182141693 %! 0.07143158068636 %! -0.05050622257469 %! 0.00821219616448 %! -0.00513106293312 %! 0.02776952210339 %! 0.03890416611405 %! 0.00032786748236 %! 0.00110112420442 %! ]'; %! [b m] = firpm (21, [0 .2 .3 .4 .5 .7 .9 1], [0 .2 0 0 .5 .7 0 0], [1 4 16 64], 'b', {256}); %! assert (b0, b, 1e-5); assert (m, 0.19215, -5e-5); %!test b0 = [ %! 0.00688473243750 %! -0.00142370547227 %! 0.00792901881787 %! 0.05914568352388 %! 0.03038499582274 %! 0.03374098557746 %! -0.02191978751853 %! -0.08702247834731 %! 0.10568616843372 %! -0.06074859970379 %! -0.18689246939614 %! 0.18689246939614 %! 0.06074859970379 %! -0.10568616843372 %! 0.08702247834731 %! 0.02191978751853 %! -0.03374098557746 %! -0.03038499582274 %! -0.05914568352388 %! -0.00792901881787 %! 0.00142370547227 %! -0.00688473243750 %! ]'; %! [b m] = firpm (21, [0 .2 .3 .4 .5 .7 .9 1], [0 .2 0 0 .5 .7 0 0], [1 4 16 64], 'h', {256}); %! assert (b0, b, 1e-5); assert (m, 0.20726, -5e-5); %!test b0 = [ %! -0.00164508269033 %! 0.00067200008069 %! 0.00268424782721 %! -0.03510524314006 %! 0.00455581822868 %! 0.00862256307919 %! 0.03221163698642 %! 0.08429446688809 %! -0.12214036419364 %! 0.04373834279952 %! 0.19029552670347 %! -0.19029552670347 %! -0.04373834279952 %! 0.12214036419364 %! -0.08429446688809 %! -0.03221163698642 %! -0.00862256307919 %! -0.00455581822868 %! 0.03510524314006 %! -0.00268424782721 %! -0.00067200008069 %! 0.00164508269033 %! ]'; %! [b m] = firpm (21, [0 .2 .3 .4 .5 .7 .9 1], [0 .2 0 0 .5 .7 0 0], [1 4 16 64], 'd', {256}); %! assert (b0, b, 1e-5); assert (m, 0.47868, -5e-5); %!test b0=[ %! -0.01402452049012097 %! 0.001876620211412957 %! 0.03037229727821556 %! -0.01238680025691372 %! -0.0170173995332925 %! -0.001299983105532321 %! -0.01887047540094186 %! 0.0478657090945251 %! 0.02646457824791903 %! -0.05579347345500663 %! -0.001118815789852797 %! -0.05887946612620026 %! 0.03589780658038378 %! 0.229839817358415 %! -0.1717538614573135 %! -0.2842595261696291 ]'; %! [b m] = firpm (31 , [0 .3 .4 .7 .8 1], [0 1 0], [10 1 10], 'a', {1}); %! assert (b, [b0 fliplr(-b0)], 5e-9); %! assert (m, 0.059734, -5e-5); %!test b0 = [ %! -8.876086291046802e-04 %! 2.355569104748801e-02 %! -8.241671888096303e-04 %! -4.470074798008300e-02 %! -2.808154545387648e-03 %! 8.170132813894931e-02 %! -1.058582827015804e-03 %! -1.777420298924492e-01 %! -2.265334116571183e-02 %! 5.239577857603830e-01 %! 8.489449590726375e-01 %! 5.239577857603830e-01 %! -2.265334116571183e-02 %! -1.777420298924492e-01 %! -1.058582827015804e-03 %! 8.170132813894931e-02 %! -2.808154545387648e-03 %! -4.470074798008300e-02 %! -8.241671888096303e-04 %! 2.355569104748801e-02 %! -8.876086291046802e-04 %! ]'; %! [b m] = firpm (N=20, [0 .4 .6 1], {@(n,f,g,w,v1) deal ((log2 (v1/n+w(2)+g)).*(g<=f(2)), ones (size(g))),2*N}); %! assert (b0, b, 1e-5); assert (m, .0210628, -5e-5); %!test [b m] = firpm (40, [0 .5 .6 1], [1 0]); %! assert (m, 0.010304, -5e-5); %!test [b m] = firpm (40, [0 .25 .3 .6 .65 1], [0 1 0]); %! assert (m, 0.055834, -5e-5); %!test [b m] = firpm (30, [0 .2 .4 .6 .8 1], [1 .5 0]); %! assert (m, 5.6277e-04, -5e-5); %!test %! [b m] = firpm (40, [0 .2 .3 .4 .5 .6 .7 .8 .9 1], [1 0 1 0 1], [11 100 7 10 5]); %! assert (m, 0.25723, -5e-5); %!test [b m] = firpm (80, [0 .2 .3 1], [1 -1]); %! assert (m, 6.6123e-04, -5e-5); %!test [b m] = firpm (40, [0 2.5/pi], [0 2.5], [.5], 'differentiator'); %! assert (m, 2.5226e-06, -5e-5); %!test [b m] = firpm (59, [0 .2 .3 1], [0 1 0 0], 'd'); %! assert (m, 0.0073785, -5e-5); %!test [b m] = firpm (31, [0 .5 .7 1], [0 1], 'antisymmetric'); %! assert (m, 0.0015660, -5e-5); %!test assert (firpm (31, [0 .5 .7 1], [0 1], 'antisymmetric'), firpm (31, [0 .5 .7 1], [0 1], 'hilbert')) %!test [b m] = firpm (30, [.1 .9], 1, 'antisymmetric'); %! assert (m, 0.0027064, -5e-5); %!test [b m] = firpm (1000, [0 .4 .41 1], [1 0]); %! assert (m, 5.2892e-05, -5e-5); %!test [b m] = firpm (120, [0 .5 .55 .75 .75 1], [1 0 0], [1 1 4 64 64 64]); %! assert (m, 0.0048543, -5e-5); %!test [b m] = firpm (11, [0 2*.45], .5, 'symmetric'); %! assert (m, 0.045066, -5e-5); %!warning firpm (298, [0 .28 .33 .48 .53 1], [0 1 0], [93 68 89], {50,-1}); %!test [b m] = firpm (298, [0 .28 .33 .48 .53 1], [0 1 0], [93 68 89], {50}); %! assert (m, 6.86583e-05, -5e-5); %!test assert (firpm (11, [0 2*.45], .5, 'symmetric'), firpm (11, [0 2*.45], .5, 'bandpass')) %!test assert (firpm (11, [0 2*.45], .5, 'symmetric'), firpm (11, [0 2*.45], .5)) %!assert (firpm (20, [0 .3 .5 1], [1 1 0 0]), firpm (20, [0 .3 .5 1], [1 0])) %!test assert ( %! firpm (30, [0.1 0.9], 1, "antisymmetric"), %! firpm (30, [0.1 0.9], 1, "hilbert")) %!test assert ( %! firpm (11, [0 0.9], 1, {1}), %! firpm (11, [0 0.9], 1, {64})) %!test %! [b1 m1] = firpm (20, [0 0.4 0.5 1], [1 0], [1 1/8]); %! [b2 m2] = firpm (20, [0 0.4 0.5 1], [1 0], [8 1]); %! assert (b1, b2) %! assert (m1 * 8, m2) %! %!demo %! %! N=38; F=[0 .47 .53 1]; A=[1 1 0 0]; W=[1 1]; ant=0; %! [b m r] = firpm (N, F, A, W, 'sa'(1+ant)); %! %! mul=[1 i](1+ant); %! clf; [h f] = freqz (b); plot (f/pi, real (mul*h.*exp (i*f*N/2)), %! f=F(1:2),(a=A(1:2))-(M=m/W(1)),'r', f, a+M,'r', %! f=F(3:4),(a=A(3:4))-(M=m/W(2)),'r', f, a+M,'r', %! r.fextr, real ((mul*r.H.*exp (i*r.fgrid*pi*N/2))(r.iextr)),'ko') %! grid on; axis ([0 1 -.1 1.1]); set (gca, 'xtick', [0:.1:1], 'ytick', [0:.1:1]) %! title (sprintf ('firpm type-I low-pass filter (order=%i)', length (b) - 1)); %! ylabel ('Amplitude response'); xlabel ('Frequency (normalized)') %! axes ('position', [.58 .35 .3 .5]) %! stem (b); grid off %! title ('Impulse response') %! axis ([1 length(b) -.15 .55]) %! %-------------------------------------------------- %! % Figure shows transfer and impulse-response of %! % half-band filter design. %! %!demo %! %! N=41; F=[0 .1 .16 .34 .4 1]; A=[0 0 1 1 0 0]; W=[1 3 2]; ant=1; %! [b m r] = firpm (N, F, A, W, 'sa'(1+ant)); %! %! mul=[1 i](1+ant); %! clf; [h f] = freqz (b); plot (f/pi, real (mul*h.*exp (i*f*N/2)), %! f=F(1:2),(a=A(1:2))-(M=m/W(1)),'r', f, a+M,'r', %! f=F(3:4),(a=A(3:4))-(M=m/W(2)),'r', f, a+M,'r', %! f=F(5:6),(a=A(5:6))-(M=m/W(3)),'r', f, a+M,'r', %! r.fextr, real ((mul*r.H.*exp (i*r.fgrid*pi*N/2))(r.iextr)),'ko') %! grid on; axis ([0 1 -.1 1.1]); set (gca, 'xtick', [0:.1:1], 'ytick', [0:.1:1]) %! title (sprintf ('firpm type-IV weighted band-pass filter (order=%i)', length (b) - 1)); %! ylabel ('Amplitude response'); xlabel ('Frequency (normalized)') %! axes ('position', [.55 .4 .3 .4]) %! stem (b); grid off %! title ('Impulse response') %! axis ([1 length(b) -.3 .3]) %! %-------------------------------------------------- %! % Figure shows transfer and impulse-response of %! % band-pass filter design. %! %!demo %! %! curve = @(a,b,y,z,x) z*(b-a)./((x-a)*z/y+b-x); %! respFn = @(n,f,g,w,curve) deal (g>=f(3) & g<=f(4), ... %! (g<=f(2)).*curve (f(2),f(1),w(1),w(3),g) + ... %! (g>=f(3) & g<=f(4))*w(2) + ... %! (g>=f(5) & g<=f(6)).*curve (f(5),f(6),w(1),w(3),g) + ... %! (g>f(7))*w(4)); % NB contiguous bands so > not >=. %! b=firpm (127, [0 .2 .24 .26 .3 .5 .5 1], {respFn, curve}, [10 1 100 10]); %! %! clf; [h f]=freqz (b); plot (f/pi, 20*log10 (abs (h))) %! grid on; axis ([0 1 -90 5]); set (gca, 'xtick', [0:.1:1], 'ytick', [-80:10:0]) %! title (sprintf ('firpm type-II band-pass filter with shaped stop-bands (order=%i)', length (b) - 1)); %! ylabel ('Magnitude response (dB)'); xlabel ('Frequency (normalized)') %! %-------------------------------------------------- %! % Figure shows transfer of band-pass filter design %! % with shaped error-weight in the stop-bands. %! %!demo %! %! b = firpm (40, [0 .1 .3 1], [-1 1]); %! %! clf; [h f] = freqz (b,1,2^14); plot (f/pi, 20*log10 (abs (h))) %! grid on; axis ([0 1 -60 5]); set (gca, 'xtick', [0:.1:1]) %! title (sprintf ('firpm type-I notch filter (order=%i)', length (b) - 1)); %! ylabel ('Magnitude response (dB)'); xlabel ('Frequency (normalized)') %! axes ('position', [.42 .55 .45 .2]) %! plot (f/pi, 20*log10 (abs (h))); grid on %! axis ([0 1 -(e=1e-2) e]) %! title ('Pass-bands detail') %! axes ('position', [.42 .2 .45 .2]) %! stem (b); grid off %! title ('Impulse response') %! axis ([1 length(b) -.45 .65]) %! %-------------------------------------------------- %! % Figure shows transfer and impulse-response of %! % notch filter design. %! %!demo %! %! b = firpm (1000, [0 .4 .41 1], [1 0], {1}); %! %! clf; [h f] = freqz (b, 1, 2^17); plot (f/pi, 20*log10 (abs (h))) %! title (sprintf ('firpm type-I brick-wall low-pass filter (order=%i)', length (b) - 1)); %! ylabel ('Magnitude response (dB)'); xlabel ('Frequency (normalized)') %! grid on; axis ([0 1 -100 5]); set (gca, 'xtick', [0:.1:1]) %! axes ('position', [.55 .6 .3 .2]) %! plot (f/pi, 20*log10 (abs (h))); grid on %! title ('Details') %! axis ([.38 .401 -(e=1e-3) e]) %! axes ('position', [.55 .3 .3 .2]) %! plot (f/pi, 20*log10 (abs (h))); grid on %! axis ([.409 .43 -86 -85]) %! axes ('position', [.2 .35 .2 .3]) %! semilogy (abs (b)); grid off %! title ('Impulse response magnitude') %! axis ([0 length(b)+1 1e-6 1]) %! %-------------------------------------------------- %! % Figure shows transfer and impulse-response of %! % brick-wall low-pass filter design. %! %!demo %! %! b = firpm (20, [0 2.5]/pi, [0 2.5], 'differentiator'); %! %! clf %! [h f] = freqz (b,1,2^12); %! subplot (2, 1, 1) %! plot (f, abs (h)); grid on %! title (sprintf ('firpm type-III differentiator filter (order=%i)', length (b) - 1)); %! ylabel ('Magnitude response'); xlabel ('Frequency (radians/sample)') %! axis ([0 pi 0 pi]) %! subplot (2, 1, 2) %! plot (f, abs (abs (h)./f-1)); grid on %! axis ([0 2.5 0 1e-3]) %! title ('Pass-band error (inverse-f weighted)') %! %-------------------------------------------------- %! % Figure shows transfer of differentiator filter design. %! % above: full-band %! % below: detail of pass-band error (inverse-f weighted) %! %!demo %! %! b = firpm (30, [.05 .95], 1, 'antisymmetric'); %! %! clf; [h f] = freqz (b); plot (f/pi, abs (h)) %! grid on; axis ([0 1 0 1.1]); set (gca, 'xtick', [0:.1:1], 'ytick', [0:.1:1]) %! title (sprintf ('firpm type-III hilbert transformer filter (order=%i)', length (b) - 1)); %! ylabel ('Magnitude response'); xlabel ('Frequency (normalized)') %! axes ('position', [.3 .25 .45 .4]) %! stem (b); grid off %! title ('Impulse response') %! axis ([1 length(b) -.7 .7]) %! %-------------------------------------------------- %! % Figure shows transfer and impulse-response of %! % hilbert filter design. %! %!demo %! cic = @(f) (sin (pi*(f+eps*!f)/2)./sin (pi*(f+eps*!f)/2/10)/10).^4; %! %! if compare_versions(OCTAVE_VERSION, '6', '<') %! eval('b = firpm (30, [0 .5 .7 1], @(n,f,g, w) deal (a=(g<=f(2))./cic (g), 1./(a+!a)));') %! else %! function [ag wg] = resp (n,f,g,w) ag = (g<=f(2))./cic (g); wg = 1./(ag+!ag); endfunction %! b = firpm (30, [0 .5 .7 1], @resp); %! endif %! %! clf; [h f]=freqz (b); plot (f/=pi, 20*log10 (abs (h))) %! grid on; axis ([0 1 -60 6]); set (gca, 'xtick', [0:.1:1]) %! title (sprintf ('firpm type-I CIC-compensation filter (order=%i)', length (b) - 1)); %! ylabel ('Magnitude response (dB)'); xlabel ('Frequency (normalized)') %! axes ('position', [2 3 4 3]/10) %! plot (f, 20*log10 (abs (h).*cic (f))); axis ([0 .55 -.04 .04]); grid on %! title ('Compensated filter response') %! %-------------------------------------------------- %! % Figure shows transfer details of CIC-compensation %! % filter design. %! %!demo %! clf; n=30; Fp=.8; for d=linspace (-.5, .5, 10) %! %! b = firpm (n, [0 Fp], {@(n,f,g,w,d,Fp) (g<=Fp).*cos (g*pi*d),d,Fp})... %! + firpm (n, [0 Fp], {@(n,f,g,w,d,Fp) (g<=Fp).*sin (g*pi*d),d,Fp}, 'a'); %! %! [g f]=grpdelay (b); %! set (gca,'ColorOrderIndex',1); plot (f/pi, g-n/2); hold ('on'); end; %! hold ('off'); grid on; axis ([0 1 -.6 .6]); set (gca, 'xtick', [0 Fp 1], 'ytick', [-.5:.5:.5]) %! title (sprintf ('firpm type-I fractional-delay filters (order=%i)', length (b) - 1)); %! ylabel ('Fractional-delay (samples)'); xlabel ('Frequency (normalized)') %! %-------------------------------------------------- %! % Figure shows delay response of (non-linear-phase) %! % filter designs with progressive fractional-delay. */ signal-1.4.5/src/medfilt1.cc0000644000000000000000000004061214456505401013776 0ustar0000000000000000/* Copyright (C) 2015-2016 Lachlan Andrew, Monash University This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, see . */ /* Author: Lachlan Andrew Created: 2015-12-13 */ /** @file libinterp/corefcn/medfilt1.cc One dimensional median filter, for real double variables. */ #include #include #include "oct.h" #include "defun-dld.h" #include "error.h" #include "ov.h" #include "octave-compat.h" enum nan_opt_type { NAN_OPT_INCLUDE, NAN_OPT_OMIT }; enum pad_opt_type { PAD_OPT_ZERO, PAD_OPT_TRUNCATE }; // Keep a sorted sliding window of values. // There is no error checking, to keep things fast. // Keeps NaNs at the "top" (after Inf) class sorted_window { std::unique_ptr buf; octave_idx_type numel; octave_idx_type numNaN; bool nan_if_any_is; // Return the index of target in the window, from element start to the end // FIXME: for large n, use binary search, but be careful to keep NaN at end octave_idx_type find (double target, octave_idx_type start = 0) { octave_idx_type i; for (i = start; i < numel; i++) if (!(buf[i] < target)) { if (target == target) // We've found the target. return i; else return numel; // target is NaN; add it to the end. } return numel; } public: // Create sorted window with maximum size width. // If skip_nan then the median will consider only valid numbers within // the window. sorted_window (octave_idx_type width, bool skip_nan = true) : buf (new double [width]), numel (0), numNaN (0), nan_if_any_is (! skip_nan) { } // Initialize to contain seed, and zeros additional zeros. void init (const double *seed, octave_idx_type num, octave_idx_type stride, octave_idx_type zeros = 0) { numel = zeros; numNaN = 0; std::fill_n (&buf[0], zeros, 0.0); // Insert from seed. Could sort if it is large num *= stride; for (octave_idx_type i = 0; i < num; i += stride) add (seed[i]); } // Take item prev from the window and replace it by next. // Assumes prev is in the window. void replace (double next, double prev) { octave_idx_type n_pos, p_pos; if (next < prev) { n_pos = find (next); p_pos = find (prev, n_pos); if (n_pos != p_pos) std::copy_backward (&buf[n_pos], &buf[p_pos], &buf[p_pos + 1]); } else if (next > prev) { p_pos = find (prev); n_pos = find (next, p_pos); if (n_pos != p_pos) { std::copy (&buf[p_pos + 1], &buf[n_pos], &buf[p_pos]); n_pos--; // position shifts due to deletion of p_pos } } else if (next != prev) // one is NaN. { if (next == next) { n_pos = find (next); std::copy_backward (&buf[n_pos], &buf[numel - 1], &buf[numel]); numNaN--; } else if (prev == prev) { p_pos = find (prev); std::copy (&buf[p_pos + 1], &buf[numel], &buf[p_pos]); n_pos = numel - 1; numNaN++; } else return; // fallthrough case (next, prev both NaN) } else // fallthrough case (next == prev) requires no action. return; buf [n_pos] = next; } // Expand the window by one element, inserting next. // This will crash if this exceeds the allocation of buf. void add (double next) { octave_idx_type n_pos; if (next == next) // not NaN { n_pos = find (next); if (n_pos < numel) std::copy_backward (&buf[n_pos], &buf[numel], &buf[numel + 1]); } else // NaN stored at end, so nothing to move. { n_pos = numel; numNaN++; } buf[n_pos] = next; numel++; } // Reduce the window by one element, deleting prev. // This will crash if the window is already empty void remove (double prev) { octave_idx_type p_pos; if (prev == prev) { p_pos = find (prev); std::copy (&buf[p_pos + 1], &buf[numel], &buf[p_pos]); } else // NaN stored at end, so nothing to move. numNaN--; numel--; } // The middle value if numel-numNaN is odd, // or the mean of the two middle values if numel-numNaN is even. // This will crash if the window is empty. double median (void) { double retval = 0; octave_idx_type non_nan_window = numel; double last = buf [numel-1]; if (last != last) // if NaN { if (nan_if_any_is) retval = last; else { non_nan_window = numel - numNaN; if (non_nan_window == 0) retval = last; } } if (retval == 0) // if result is not NaN { if (non_nan_window & 1) retval = buf[non_nan_window >> 1]; else { octave_idx_type mid = non_nan_window >> 1; retval = (buf[mid - 1] + buf[mid]) / 2; } } return retval; } }; // Median filter on a single vector, // starting at x with values spaced by stride. // The output is placed into y, with the same stride. static inline void medfilt1_vector (double *x, double *y, octave_idx_type n, octave_idx_type len, octave_idx_type stride, octave_idx_type leading, octave_idx_type trailing, octave_idx_type start_middle, octave_idx_type end_middle, octave_idx_type last, octave_idx_type initial_fill, pad_opt_type pad_opt, sorted_window& sw) { sw.init (x, initial_fill, stride, (pad_opt == PAD_OPT_ZERO) ? (n - initial_fill) : 0); // Partial window at the start if (pad_opt == PAD_OPT_ZERO) for (octave_idx_type i = 0; i < start_middle; i += stride) { sw.replace (x[i + leading], 0); y[i] = sw.median (); } else for (octave_idx_type i = 0; i < start_middle; i += stride) { sw.add (x[i + leading]); y[i] = sw.median (); } if (n < len) // Full sized window for (octave_idx_type i = start_middle; i < end_middle; i += stride) { sw.replace (x[i + leading], x[i - trailing]); y[i] = sw.median (); } else { // All of x is in the window double m = sw.median (); for (octave_idx_type i = start_middle; i < end_middle; i += stride) y[i] = m; } // Partial window at the end if (pad_opt == PAD_OPT_ZERO) for (octave_idx_type i = end_middle; i < last; i += stride) { sw.replace (0, x[i - trailing]); y[i] = sw.median (); } else for (octave_idx_type i = end_middle; i < last; i += stride) { sw.remove (x[i - trailing]); y[i] = sw.median (); } } DEFUN_DLD(medfilt1, args, , " -*- texinfo -*- \n\ @deftypefn {} {@var{y} =} medfilt1 (@var{x}, @var{n})\n\ @deftypefnx {} {@var{y} =} medfilt1 (@var{x}, @var{n}, [], @var{dim})\n\ @deftypefnx {} {@var{y} =} medfilt1 (..., @var{NaN_flag}, @var{padding})\n\ \n\ Apply a one dimensional median filter with a window size of @var{n} to\n\ the data @var{x}, which must be real, double and full.\n\ For @var{n} = 2m+1, @var{y}(i) is the median of @var{x}(i-m:i+m).\n\ For @var{n} = 2m, @var{y}(i) is the median of @var{x}(i-m:i+m-1).\n\ \n\ The calculation is performed over the first non-singleton dimension, or over\n\ dimension @var{dim} if that is specified as the fourth argument. (The third\n\ argument is ignored; Matlab used to use it to tune its algorithm.)\n\ \n\ @var{NaN_flag} may be @qcode{omitnan} or @qcode{includenan} (the default).\n\ If it is @qcode{omitnan} then any NaN values are removed from the window\n\ before the median is taken.\n\ Otherwise, any window containing an NaN returns a median of NaN.\n\ \n\ @var{padding} determines how the partial windows at the start and end of\n\ @var{x} are treated.\n\ It may be @qcode{truncate} or @qcode{zeropad} (the default).\n\ If it is @qcode{truncate} then the window for @var{y}(i) is\n\ the intersection of the window stated above with 1:length(@var{x}).\n\ If it is @qcode{zeropad}, then partial windows have additional zeros\n\ to bring them up to size @var{n}.\n\ \n\ @seealso{filter, medfilt2}\n\ @end deftypefn") { if (args.length () < 1) print_usage (); octave_idx_type n = 3, dim = 0; nan_opt_type nan_opt = NAN_OPT_INCLUDE; pad_opt_type pad_opt = PAD_OPT_ZERO; int nargin = args.length (); Array signal = args(0).array_value (); // parse arguments. // FIXME: This allows repeated arguments like // medfilt1(..., "truncate", "zeropad") while (args(nargin - 1).is_string ()) { if (nargin < 2) print_usage (); std::string s = args(nargin - 1).string_value (); if (! strcasecmp (s.c_str (), "omitnan")) nan_opt = NAN_OPT_OMIT; else if (! strcasecmp (s.c_str (), "truncate")) pad_opt = PAD_OPT_TRUNCATE; else if (strcasecmp (s.c_str (), "includenan") && strcasecmp (s.c_str (), "zeropad")) // the defaults error ("medfilt1: Invalid NAN_FLAG or PADDING value '%s'", s.c_str ()); nargin--; // skip this for parsing the numeric args } if (nargin >= 2) { if (octave::signal::isnumeric (args(1))) { if (args(1).numel () != 1 || octave::signal::iscomplex (args(1))) error ("medfilt1: N must be a real scalar"); else n = args(1).idx_type_value (); } else error ("medfilt1: Invalid type for N: %s", args(1).type_name ().c_str ()); if (nargin >= 4) { if (octave::signal::isnumeric (args(3))) { if (args(3).numel () != 1) error ("medfilt1: DIM must be a scalar"); else if (octave::signal::iscomplex (args(3))) error ("medfilt1: DIM must be real"); dim = round (args(3).double_value ()); if (dim != args(3).double_value ()) error ("medfilt1: DIM must be an integer, not %g", args(3).double_value ()); //if (dim < 1 || dim > signal.dims ().length ()) if (dim < 1) error ("medfilt1: DIM must be positive, not %ld", static_cast (dim)); } else error ("medfilt1: Invalid type for DIM: %s", args(1).type_name ().c_str ()); if (nargin > 4) error ("medfilt1: Too many input arguments"); } } // Guard again divide-by-zero later. // This is the last "early return". if (args(0).numel () == 0) return ovl (args(0)); // The following code is based on filter.cc dim_vector x_dims = args(0).dims (); if (dim < 1) dim = x_dims.first_non_singleton (); else dim--; // make 0-based, not 1-based octave_idx_type x_len = x_dims (dim); octave_idx_type x_stride = 1; for (octave_idx_type i = 0; i < dim; i++) x_stride *= x_dims(i); MArray x = args(0).array_value (); MArray retval; retval.resize (x_dims, 0.0); double *p_in = x.fortran_vec (); double *p_out = retval.fortran_vec (); sorted_window sw (n, nan_opt == NAN_OPT_OMIT); // how far ahead should data be put in window octave_idx_type leading = ((n - 1) / 2) * x_stride; // how far back should data be removed from wdw octave_idx_type trailing = n * x_stride - leading; // last position in this slice octave_idx_type last = x_len * x_stride; // start of the "middle" phase with fixed window size octave_idx_type start_middle; // end of the "middle" phase with fixed window size octave_idx_type end_middle; // start window with x(1:initial_fill) octave_idx_type initial_fill = (n - 1) / 2; if (n < x_len) // small window: { // The middle phase is when replacing window elements. start_middle = trailing; end_middle = last - leading; } else // big window: { // The middle phase has whole input in the window. if (n < 2 * x_len) { start_middle = last - leading; end_middle = trailing; } else // huge window: all answers are just the median of x. { start_middle = 0; end_middle = last; initial_fill = x_len; } } octave_idx_type x_num = x_dims.numel () / x_len; octave_idx_type x_offset = 0, inner_offset = 0; for (octave_idx_type num = 0; num < x_num; num++) { medfilt1_vector (p_in + x_offset, p_out + x_offset, n, x_len, x_stride, leading, trailing, start_middle, end_middle, last, initial_fill, pad_opt, sw); if (x_stride == 1) x_offset += x_len; else { x_offset++; if (++inner_offset == x_stride) { inner_offset = 0; x_offset += x_stride * (x_len - 1); } } } return ovl (retval); } /* %!assert (medfilt1 ([1 2 3 4 3 2 1]), [1 2 3 3 3 2 1]); %!assert (medfilt1 ([1 2 3 4 3 2 1]'), [1 2 3 3 3 2 1]'); %!assert (medfilt1 ([1 2 3 4 3 2 1], "truncate"), [1.5 2 3 3 3 2 1.5]); %!assert (medfilt1 ([-1 2 3 4 3 -2 1], "truncate"), [0.5 2 3 3 3 1 -0.5]); %!assert (medfilt1 ([-1 2 3 4 3 -2 1], "zeropad"), [0 2 3 3 3 1 0]); %!assert (medfilt1 ([]), []); %!test %! A = [1 2 3 ; 6 5 4 ; 6 5 2 ]; %! assert (medfilt1 (A,4,[],2), [0.5 1.5 1.5; 2.5 4.5 4.5; 2.5 3.5 3.5]); %! assert (medfilt1 (A,4,[],1), [0.5 3.5 3.5; 1 3.5 3.5; 1.5 2.5 2.5]'); %! assert (medfilt1 (A,3,[],1), [1 2 3; 6 5 3; 6 5 2]); %!test %! A = [ Inf 4 -4 NaN -1 -1 -3 -2 1 -Inf]; %! B = medfilt1 (A, 7, [], 1, 'includenan', 'zeropad'); %! assert (B, [0, 0, 0, NaN, 0, 0, 0, 0, 0, 0]); %! B = medfilt1 (A, 7, [], 2, 'includenan', 'zeropad'); %! assert (B, [NaN, NaN, NaN, NaN, NaN, NaN, NaN, -1, -1, 0]); %! B = medfilt1 (A, 7, [], 2, 'includenan', 'truncate'); %! assert (B, [NaN, NaN, NaN, NaN, NaN, NaN, NaN, -1.5, -2, -2.5]); %! B = medfilt1 (A, 7, [], 2, 'omitnan', 'zeropad'); %! assert (B, [0, 0, -0.5, -1, -1.5, -1.5, -1.5, -1, -1, 0]); %! B = medfilt1 (A, 7, [], 2, 'omitnan', 'truncate'); %! assert (B, [4, 1.5, -1, -1, -1.5, -1.5, -1.5, -1.5, -2, -2.5]); %!test %! A = medfilt1 ([ NaN NaN -Inf], 4, [], 2, 'omitnan', 'truncate'); %! assert (A, [NaN, -Inf, -Inf]); %!test %! A = medfilt1 ([-2 Inf -2; 1 3 -Inf; 1 0 -Inf], 1, [], 2); %! assert (A, [-2 Inf -2; 1 3 -Inf; 1 0 -Inf]); %!test %! A = medfilt1 ([-Inf 0 -3; Inf 1 NaN], 9, [], 1); %! assert (A, [0, 0, NaN; 0, 0, NaN]); %! A = medfilt1 ([-Inf 0 -3; Inf 1 NaN], 9, [], 1, 'omitnan', 'truncate'); %! assert (A, [NaN, 0.5, -3; NaN, 0.5, -3]); %!test %! A = medfilt1 ([Inf -3 Inf Inf 0 -2; Inf 1 NaN 5 5 -3], 3, [], 1); %! assert (A, [Inf, 0, NaN, 5, 0, -2; Inf, 0, NaN, 5, 0, -2]); %!test %! A = medfilt1 ([3 3 7 5 6]', 5, [], 1, 'omitnan', 'truncate'); %! assert (A, [3, 4, 5, 5.5, 6]'); %! A = medfilt1 ([3 3 7 5 6]', 5, [], 2, 'omitnan', 'truncate'); %! assert (A, [3, 3, 7, 5, 6]'); %!test %! A = medfilt1 ([3 1 4 1 3], 3, 'omitnan', 'truncate'); %! assert (A, [2, 3, 1, 3, 2]); %!test %! A = medfilt1 ([3 1 4 1 3], 6, 'omitnan', 'truncate'); %! assert (A, [3, 2, 3, 3, 2]); %!test %! A = medfilt1 ([1 2 3 4 4 3 2 1; 6 5 4 3 3 4 5 6; 6 5 4 3 2 1 0 -1; 6 5 4 3 2 1 0 -1]); %! assert (A, [1 2 3 3 3 3 2 1; 6 5 4 3 3 3 2 1; 6 5 4 3 2 1 0 -1; 6 5 4 3 2 1 0 -1]); # Input checking %!error (medfilt1 ([1 2 3], -1)); %!error (medfilt1 ([1 2 3], 1, [], "hello")); %!error (medfilt1 ([1 2 3], 1, [], "omitnan", false)); %!error (medfilt1 ({1 2 3})); */ signal-1.4.5/src/mmfir.c0000644000000000000000000005575014456505401013251 0ustar0000000000000000// mmfir.c: MiniMax FIR filter design per McClellan, Parks & Rabiner // Copyright (c) 2014/15/21 Rob Sykes // // mmfir is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation; either version 3 of the License, or (at your option) any later // version. // // mmfir is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR // A PARTICULAR PURPOSE. See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along with // this program; if not, see . #include "mmfir.h" #if defined QUAD_PREC #include #endif #include #include #include #include #include #if INT_MAX == 2147483647 typedef int rand_t; #elif LONG_MAX == 2147483647L typedef long rand_t; #else #error no suitable int32 type #endif #if defined _MSC_VER #define inline __inline #endif // Real-number precision, quad, double or long double (the default). #if defined QUAD_PREC // Very slow without native support. typedef __float128 real; #define cosr cosq #define sinr sinq #define PIr M_PIq #elif defined DOUBLE_PREC typedef double real; #define cosr cos #define sinr sin #define PIr PI #else typedef long double real; #define cosr cosl #define sinr sinl #define PIr 3.1415926535897932384626433832795029L #endif #define bandL (&bandSpecs[0]) #define bandR (&bandSpecs[numBands-1]) #define clamp(x,lo,hi) (((x)>(hi))?(hi):(((x)<(lo))?(lo):(x))) #define debugLevel (flags & 3) #define dir(x) ((x)<0? -1: (x)>0? 1 : 0) #define epsilon 1e-11 // In some circumstances, treat < epsilon as 0 #define E(x) peaks[x].e #define e(x) space[x].e #define F(x) peaks[x].f #define f(x) space[x].f #define maxExtras (numBands+2) #define maxPeaks (R+1+maxExtras) #define PI 3.1415926535897932384626433832795029 #define rand(r,x) (ranqd1(r) * ((x) / (65536. * 32768.))) // in [-x,x) #define ranqd1(r) ((r) = 1664525 * (r) + 1013904223) // int32_t r #define returnError(x) do {report.result=x; goto END;} while(0) #define iround(x) (int)floor((x)+.5) #define setF(F) for (f=(F); f>b->freqR; ++b) #define userEpsilon 1e-6 #define hasConverged(len) (((minimality = minimality_(peaks, len, \ minimalityThreshold))>0 && (density2)) || stability>2.7) static inline double maxD(double a, double b) {return a>=b? a:b;} static inline int maxI(int a, int b) {return a>=b? a:b;} static char const * const errorText[]={ "out-of-memory", "number of bands must be at least 1", "filter-order must be at least 1", "band-edge frequencies must increase in [0,1]", "weighting function out-of-range", "amplitude function out-of-range", "type III/IV DC amplitude response must be 0", "type II/III Nyquist amplitude response must be 0", }; // Type definitions: typedef enum {TypeI, TypeII, TypeIII, TypeIV} FirType; typedef struct {real x, beta, gamma;} LagrangeCoef; typedef MmfirPoint Point; // Determine coefs of a 2nd-order polynomial from 3 of its points: static void poly2( double x0, double x1, double x2, double y0, double y1, double y2, double * a, double * b, double * c) { double a0 = y0/((x0-x1)*(x0-x2)); double a1 = y1/((x1-x2)*(x1-x0)); double a2 = y2/((x2-x0)*(x2-x1)); *a = a0+a1+a2; *b = -(a0*(x1+x2) + a1*(x0+x2) + a2*(x0+x1)); *c = a0*x1*x2 + x0*a1*x2 + x0*x1*a2; } // Evaluate a 2nd-order polynomial at given point: static double poly2Val(double a, double b, double c, double x) { return (a*x + b)*x + c; } /* For filter-response analysis, use a discrete frequency space that is * 'warped' around transition-bands. The warping function is derived from the * observation by Shpak/Antoniou (1990) that an 'initial guess' for the peak * frequencies based on adjacent-peak spacing proportional to s(n) = * exp(c1+c2*n), improves upon one where the adjacent-peak spacing is constant. * * E.g., for a band-pass filter with band-edges 0, s1, p1, p2, s2, 1, the * analysis points within warped space compared to those in a linear space * might look like the following (second stop-band not shown): * 0 s1 p1 p2 * Warped: o o o o o oo oo o o o o o o o oo * Linear: o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o * * Warp function derivation is as follows: approx. peak position continuous * function, warp(x) = * x>=1: f(x)-f(0) * x<1: 2nd-order approximation (since exp. approx. breaks down here) * where f(x) = Indef. integral of s(x) = exp(c1+c2*x)/c2 * * Constants c1, c2 are determined empirically. Dependent constants c3=-f(0), * ca,cb,cc are calculated as follows: c3 = -exp(c1)/c2; * poly2(0,1,2, 0,warp(1),warp(2), &ca,&cb,&cc); */ static double const c1 = +.1235; static double const c2 = -.8; static double const c3 = 1.41431; static double const ca = .214437; static double const cb = .006742; static double const cc = 0; static double warp(double x) // Calculate warp in arbitrary units: { double t = c1 + c2*x; return x<0? 0 : x<1? poly2Val(ca,cb,cc,x) : x-(t>-38? exp(t)/c2 : 0)-c3; } static double iwarp(double y) // Inverse of warp(). { double t, x1=y+c3, x; if (y<0) return 0; if (y-38? exp(t) : 0)); while (fabs(x1-x)>1e-5); return x1; } // Generate a set of warped frequency-space points. // N.B. rand helps to avoid Lagrange interpolation instability: static int warpSpace(Point * p, double m, double f1, double f2, int density, int step, rand_t * random) { int i, n = (int)ceil(m*density); double scale, df = f2 - f1; p->f = f1, p+=step; // End points must be exact (not calculated). if (n > 0) { scale = df/warp(1.*n/density); for (i = 1; i < n; ++i) p->f = f1+scale*warp((i+rand(*random, .001))/density), p+=step; p->f = f2; // End points must be exact (not calculated). } return 1+n; } static int warpSpaceR( // Right of transition-band. Point * p, double m, double f1, double f2, int density, rand_t * random) { return warpSpace(p, m, f1, f2, density, +1, random); } static int warpSpaceL ( // Left of transition-band. Point * p, double m, double f1, double f2, int density, rand_t * random) { return warpSpace(p+(int)ceil(m*density), m, f2, f1, density, -1, random); } static int warpSpaceRL( // Between transition-bands. Point * p, double m, double f1, double f2, int density, rand_t * random) { double df1 = (f2 - f1) * .5, m1 = m * .5; int n = warpSpaceR(p, m1, f1, f1+df1, density, random); warpSpaceL(p + n-1, m1, f1+df1, f2, density, random); return n*2-1; } // Apportion space to each band, taking account of warping: static void apportionSpace(MmfirBandSpec * b, int numBands, int n) { int i, changed; double sum, t, av; do { // Use an iterative method. for (av=changed=0, i=0; i 1e-6; sum+= b[i].portion=t; } for (i=0; i 1e+10) return MmfirInvalidAmplitude; if (w < 1e-10 || w > 1e+10) return MmfirInvalidWeight; } if (maxA<1e-20) return MmfirInvalidAmplitude; } if (T) for (i=0; iweightF?f:1)); } return MmfirSuccess; } // Calculate the estimated amplitude response at a single, given // frequency using precalculated Lagrange interpolation coefficients. static real A(LagrangeCoef const * coefs, int R, double f) { int i = 0; real n = 0, d = 0, x = cosr(PIr*f), t; for (; i < R; d += t = coefs[i].beta / t, n += coefs[i].gamma * t, ++i) if (fabs((double)(t = x - coefs[i].x)) < epsilon) return coefs[i].gamma; return n/d; } static MmfirResult builtInRespFn( // For simple response, given in bandSpecs: MmfirBandSpec const * b, int len, Point * p, va_list args) { (void)args; int i; double f; for (i=0; iweightL + b->weightR*(f-b->freqL)); p[i].a= (b->ampL + b->ampR *(f-b->freqL)); } return MmfirSuccess; } static double minimality_(Point const * p, int len, double threshold) { // Determine the minimality of the maximum error: double max=1+1e-9; while (len--) max=maxD(max, fabs(p[len].w)); return -log10(max-1)-threshold; } MmfirReport mmfir( double h[], MmfirFilterClass filterClass, int N0, // = filter order + 1 int numBands, MmfirBandSpec bandSpecs[/* numBands */], // N.B. destroyed. double accuracy, double persistence, double robustness, double target, int flags, MmfirState * state, MmfirRespFn respFn, ...) { int N = maxI(N0,2); FirType T = (FirType)((filterClass!=MmfirSymmetric)*2 + !(N&1)); int R = N/2 + !T; // R = # of cosine functions; num peaks = R+1 MmfirReport report = {MmfirSuccess, 0, 0, 0, 0, {0,0,0}}; // For forward-compatibility of the use of the control // variables, (almost) silently ignore out-of-range values: int density2 = iround((5+(numBands>2))*(1+( report.controls[0]=clamp(accuracy,0,7) ))); int maxIterations = iround(128*pow(1.587, report.controls[1]=clamp(persistence,-3,3) )); int density = 3+(numBands>2)+iround( report.controls[2]=clamp(robustness,0,3) ); int doneInit=0, doLG=1; // For the lower/higher density passes. int spaceLength=0, i, j, _1; // _1 holds +/- 1 int prevNumPeaks=0; double f; double delta_1 = 1e-30; // 1/delta double totalWidth=0; // Of given bands; in which peaks will be distributed. MmfirBandSpec * b; // Allocate the working arrays: LagrangeCoef * coefs = calloc((size_t)(R+1), sizeof(*coefs)); Point * peaks = calloc((size_t)(maxPeaks), sizeof(*peaks)); Point * prevPeaks = calloc((size_t)(maxPeaks), sizeof(*prevPeaks)); Point * space0 = 0, * space = 0; // Need to determine its size first. MmfirResult err; va_list respFnArgs, tmpArgs; va_start(respFnArgs, respFn); if (!respFn) respFn = builtInRespFn; // Initial checks: if (numBands<=0) returnError(MmfirInvalidNumBands); if (N!=N0) returnError(MmfirInvalidOrder); if (bandL->freqL<0 || bandR->freqR>1) returnError(MmfirInvalidFrequency); // Further checks, and pre-calc. linear interp. gradients, etc.: for (b=bandL; b<=bandR; ++b) { double df = b->freqR - b->freqL; if ((df <= userEpsilon) || (bfreqR>(b+1)->freqL)) returnError(MmfirInvalidFrequency); if (respFn==builtInRespFn) { if (filterClass==MmfirDifferentiator) b->ampL *= -1, b->ampR *= -1; b->weightF = filterClass==MmfirDifferentiator && (fabs(b->ampL) > userEpsilon || fabs(b->ampR) > userEpsilon); if (b->weightF) b->weightL *= 2, b->weightR *= 2; // For 2/f weighting. b->ampR = (b->ampR - b->ampL ) / df; b->weightR = (b->weightR - b->weightL) / df; } else b->weightF=0; totalWidth += df; } // Avoid dividing by typeMod(0,T)=0: if ((T == TypeIII || T == TypeIV) && (b=bandL)->freqL < (f=epsilon)) { Point p = {b->freqL,0,0,0}; va_copy(tmpArgs, respFnArgs), err=respFn(b,1,&p,tmpArgs), va_end(tmpArgs); if (err) returnError(err); if (fabs(p.a) > userEpsilon) returnError(MmfirInvalidDcAmplitude); if (respFn==builtInRespFn) { b->ampL += b->ampR*(f-b->freqL); b->weightL += b->weightR*(f-b->freqL); } totalWidth -= f-b->freqL, b->freqL = f; } // Avoid dividing by typeMod(1,T)=0: if ((T==TypeII || T==TypeIII) && (b=bandR)->freqR > (f=1-epsilon)) { Point p = {b->freqR,0,0,0}; va_copy(tmpArgs, respFnArgs), err=respFn(b,1,&p,tmpArgs), va_end(tmpArgs); if (err) returnError(err); if (fabs(p.a) > userEpsilon) returnError(MmfirInvalidNyquistAmplitude); totalWidth -= b->freqR-f, b->freqR = f; } // Separate any contiguous bands: for (b=bandL; bfreqR > (f = b[1].freqL-epsilon)) totalWidth -= b->freqR-f, b->freqR = f; // Usually, start with a lower density, then switch to the final value: for (density2=maxI(density,density2); report.result==MmfirSuccess && density<=density2; doLG=0, density+=maxI(density2-density,1)) { // Map current density to a convergence minimality threshold: double minimalityThreshold = density1) fprintf(stderr, "minimalityThreshold: %g\n", minimalityThreshold); { // Allocate & populate the analysis frequency space: rand_t random = 0; for (b=bandL; b<=bandR; ++b) { double df = b->freqR - b->freqL; b->portion = b->portion0 = df/totalWidth; b->ends=2-(b->freqL <= epsilon || b->freqR >= 1-epsilon); } apportionSpace(bandL, numBands, R+1); // Determine # of points in analysis space: for (spaceLength=0, b=bandL; b<=bandR; b->endP=spaceLength, ++b) { double m = (R+1)*b->portion; if (b->freqL <= epsilon || b->freqR >= 1-epsilon) spaceLength += 1 + (int)ceil(m*density); else spaceLength += 2 * (1 + (int)ceil(m*.5*density)) - 1; } // Allocate space and calculate frequencies: free(space0); if ((space0 = (Point *)calloc((size_t)(spaceLength+2), sizeof(*space)))) { space = space0+1; // Simplifies peak detection at edges of space. for (j=0, b = bandL; b<=bandR; ++b) { double m = (R+1)*b->portion; if (b->freqL <= epsilon) j+= warpSpaceL(space+j, m, b->freqL, b->freqR, density, &random); else if (b->freqR >= 1-epsilon) j+= warpSpaceR(space+j, m, b->freqL, b->freqR, density, &random); else j+= warpSpaceRL(space+j, m, b->freqL, b->freqR, density, &random); } err = respFnMod( respFn, T, bandL, spaceLength, space, !doneInit, respFnArgs); if (err) returnError(err); } } if (!space0 || !coefs || !peaks || !prevPeaks) returnError(MmfirOutOfMemory); // Initial 'guess' distributes peaks evenly through warped space. The // offset of half a step at each end facilitates longer filters: if (!doneInit++) for (i=0; i<=R; ++i) peaks[i].f=space[iround((i+.5)/(R+1)*(spaceLength-1))].f; report.result=MmfirOngoing; while (1) { // Perform the Remez exchange (until break, below): double max, minimality, stability=0; int numPeaks, ok, extras=0; if (doLG++) { // Calculate Lagrange coefficients for response estimate: real denom = 0, numer = 0, t1, t, delta; err=respFnMod(respFn, T, bandL, R+1, peaks, 0, respFnArgs); if (err) returnError(err); for (i=0; i<=R; ++i) coefs[i].x = cosr(PIr * peaks[i].f); for (_1 = -1, b=bandL, i=0; i <= R; ++i) { for (t=1, j=0; j<=R; t1=t, t*=2*(coefs[i].x-coefs[j].x) +(i==j), ++j); if (!t1 || !t) returnError(MmfirNumericalError); coefs[i].beta = 1/t1; // Value at i==R will not be used. numer += peaks[i].a/t, denom += (_1 = -_1)/(t*peaks[i].w); } if (!numer || !denom) returnError(MmfirNumericalError); delta_1 = 1/(double)(delta = numer/denom); for (_1 = -1, b=bandL, i=0; i < R; ++i) coefs[i].gamma = peaks[i].a-(_1 = -_1)*delta/peaks[i].w; } // Stop Remez here if converged or no iterations remain: if (report.result == MmfirSuccess) break; else if (report.iterations == maxIterations) { report.result = densityendP, ++b) #ifdef _OPENMP #pragma omp parallel for #endif for (j=i; jendP; ++j) { // omp needs separate counter j here. Point * const p = space+j; p->e = delta_1 * (double)(p->w * (p->a - A(coefs, R, p->f))); } report.FEs += spaceLength; // Find and store all local peaks in error magnitude: b=bandL, numPeaks=0; for (i=0; ifreqR) + (f(i) == b->freqL); // Band-edge back-off poly2(f(j-1), f(j), f(j+1), e(j-1), e(j), e(j+1), &A, &B, &C); fp = B/A*-.5; // Freq. at which 1st derivative of poly is 0. ok = j==i || (dir(e(j+1)-e(j))*dir(e(j)-e(j-1)) > 0 && fp >= f(i-(j<=i)) && fp <= f(i+(j>=i))); // Band-edge needs care. f = ok? fp : f, e = ok? poly2Val(A,B,C,f) : e(i); // Store the peak: But avoid twin- \_ if (!numPeaks || f>peaks[numPeaks-1].f) { /* peaks in this case: \ */ if (numPeaks == maxPeaks) // Likely due to numerical error. returnError(MmfirTooManyPeaks); peaks[numPeaks].w=peaks[numPeaks].e=e, peaks[numPeaks++].f=f; // (1) } } if (debugLevel>2) { // Dump arrays to files for debugging: char name[9], dummy = (char)sprintf(name, "sp%i", report.iterations); FILE * f = fopen(name,"w") + 0*dummy; for (i=0; iR+1 peaks, reduce to R+1 by discarding lesser peaks/pairs: while (numPeaks>R+1) { int n=1, try2, d_na, d; // d = index of peak to discard. // Find a lesser peak, either overall or at one end: try2=numPeaks-(R+1)>1, i=try2? 1 : numPeaks-1; for (d_na=d=0; !d_na && i0? i : d_na; // Check alternating. d = fabs(E(i)) < fabs(E(d))? i : d; // Check magnitude. } d=d_na? d_na: d; // Prefer to discard non-alternating. if (try2 && d && d != numPeaks-1) // Discard pair only if not at end. n=2, d-=fabs(E(d-1))1) fprintf(stderr, "x%i %i:%i\n", d_na, d, n); } if (hasConverged(R+1)) report.result = MmfirSuccess; if (debugLevel) fprintf(stderr, "%2i %2i %2i % .2f % .2f\n", report.iterations, density, extras, maxD(minimality,-9.99), stability); } } if (target && 1/fabs(delta_1) > target) returnError(MmfirMissedTarget); { // Generate filter coefficients: double * a = (double *)prevPeaks; // Reuse, as it's no longer in use. double _1 = T>TypeII? -1:1, phi = (T time-domain using symmetry-aware IDFT (could also use IFFT): a[N/2] /= 1+T/3; #ifdef _OPENMP #pragma omp parallel for #endif for (i=0; i <(N+1)/2; ++i) { for (s=*a*.5, j=1; j <= N/2; s += sin(PI*((N-1-2.*i)/N*j+phi))*a[j], ++j); h[i] = _1*(h[N-1-i] = 2*s/N); } } END: if (state) { // Needed only for Octave/Matlab: free(space0), space0=0; int s0=iround(totalWidth*R*pow(4,2+accuracy)), s=0; for (j=0, b = bandL; b<=bandR; ++b) s += maxI(2, iround(b->portion*s0)); int S=s+numBands; if ((space = (Point *)calloc((size_t)S, sizeof(*space)))) { for (j=0, b = bandL; b<=bandR; ++b) { int m = maxI(2, iround(b->portion*s0)); for (i=0; ifreqL+(b->freqR-b->freqL)/m*i; space[j++].f=b->freqR; } va_copy(tmpArgs,respFnArgs),respFn(bandL,S,space,tmpArgs),va_end(tmpArgs); } state->space = space, space=0; state->peaks = peaks, peaks=0; state->spaceLength=S; state->peaksLength=R+1; } va_end(respFnArgs); free(space0); free(prevPeaks); free(peaks); free(coefs); // Complete and return the report: report.text = report.result >= MmfirInvocationError? errorText[report.result-MmfirInvocationError] : report.result >= MmfirError? "numerical-error" : report.result >= MmfirWarning? "not-converged" : "success"; report.minimax = 1/fabs(delta_1); return report; } signal-1.4.5/src/mmfir.h0000644000000000000000000000754414456505401013254 0ustar0000000000000000// mmfir.h: MiniMax FIR filter design per McClellan, Parks & Rabiner // Copyright (c) 2014/15/21 Rob Sykes // // mmfir is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation; either version 3 of the License, or (at your option) any later // version. // // mmfir is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR // A PARTICULAR PURPOSE. See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along with // this program; if not, see . #if !defined mmfir_included #define mmfir_included #include #if defined __cplusplus extern "C" { #endif typedef enum { MmfirSymmetric, // Type I/II (symmetric impulse-response). MmfirAntiSymmetric, // Type III/IV (anti-symmetric impulse-response). MmfirDifferentiator // Ditto, but with passband error-weighting *= 2/f } MmfirFilterClass; typedef struct { double freqL, freqR; // Frequency at left & right band-edges. In [0,1] double ampL, ampR; // Desired amplitude of response at given edges. double weightL, weightR; // Error weighting (multiplier) at given edges. // Internal use only: int ends, weightF, endP, hadRemoval; double eAv, ePk; double portion0, portion; } MmfirBandSpec; typedef enum { MmfirSuccess, MmfirWarning, // Section marker MmfirGaveUp = MmfirWarning, MmfirGaveUp1, // During first pass. // No filter will be returned: MmfirMissedTarget, MmfirError, // Section marker MmfirTooFewPeaks = MmfirError, MmfirTooManyPeaks, MmfirNumericalError, MmfirInvocationError, // Section marker MmfirOutOfMemory = MmfirInvocationError, MmfirInvalidNumBands, MmfirInvalidOrder, MmfirInvalidFrequency, MmfirInvalidWeight, MmfirInvalidAmplitude, MmfirInvalidDcAmplitude, MmfirInvalidNyquistAmplitude, // Internal use only: MmfirRuntimeError, MmfirOngoing } MmfirResult; typedef struct { // Useful stuff: MmfirResult result; // As defined above. char const * text; // Textual version of result. double minimax; // Final approximated minimax weighted error. // Academic interest: int FEs; // # of Lagrange interp. fn. evaluations made. int iterations; // # of Remez iterations made. double controls[3]; // Allows client to know if these were clamped. } MmfirReport; typedef struct { double f; // Frequency in [0,1] of this point double a; // Desired amplitude response @ this point. double w; // Error weight @ this point. double e; // Internal use only. } MmfirPoint; typedef struct { MmfirPoint * space; MmfirPoint * peaks; int spaceLength; int peaksLength; } MmfirState; typedef MmfirResult (* MmfirRespFn)( MmfirBandSpec const * bandSpecs, // As bandSpecs below. int numPoints, MmfirPoint points[/* numPoints */], // Provide .a & .w for each .f va_list additionalArgs); MmfirReport mmfir( double h[], // In which to store the N filter coeffiecients. MmfirFilterClass filterClass, int N, // = filter order + 1 int numBands, MmfirBandSpec bandSpecs[/* numBands */], // N.B. destroyed. double accuracy, double persistence, double robustness, double target, int flags, MmfirState * reserved, // Set to 0. MmfirRespFn respFn, // Set to 0 if resp. is given in bandSpecs. ...); // Additional args for (non-zero) respFn. #if defined __cplusplus } #endif #endif signal-1.4.5/src/octave-compat.h0000644000000000000000000000472714456505401014704 0ustar0000000000000000/* Copyright (C) 2018-2019 Mike Miller This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, see . */ #if ! defined (octave_signal_octave_compat_h) #define octave_signal_octave_compat_h #include #include #if (! defined (OCTAVE_MAJOR_VERSION) || ! defined (OCTAVE_MINOR_VERSION) \ || (OCTAVE_MAJOR_VERSION < 4) \ || ((OCTAVE_MAJOR_VERSION == 4) && (OCTAVE_MINOR_VERSION < 2))) # include #else # include #endif #if (! defined (OCTAVE_MAJOR_VERSION) || ! defined (OCTAVE_MINOR_VERSION) \ || (OCTAVE_MAJOR_VERSION < 4) \ || ((OCTAVE_MAJOR_VERSION == 4) && (OCTAVE_MINOR_VERSION < 2))) inline void err_wrong_type_arg (const char *name, const octave_value& tc) { gripe_wrong_type_arg (name, tc); } namespace octave { namespace math { inline int nint (double x) { return NINT (x); } } } #endif namespace octave { namespace signal { #if (! defined (OCTAVE_MAJOR_VERSION) || ! defined (OCTAVE_MINOR_VERSION) \ || (OCTAVE_MAJOR_VERSION < 4) \ || ((OCTAVE_MAJOR_VERSION == 4) && (OCTAVE_MINOR_VERSION < 4))) inline bool iscomplex (const octave_value& v) { return v.is_complex_type (); } inline bool isnumeric (const octave_value& v) { return v.is_numeric_type (); } inline bool isreal (const octave_value& v) { return v.is_real_type (); } inline bool iscell (const octave_value& v) { return v.is_cell (); } #else inline bool iscomplex (const octave_value& v) { return v.iscomplex (); } inline bool isnumeric (const octave_value& v) { return v.isnumeric (); } inline bool isreal (const octave_value& v) { return v.isreal (); } inline bool iscell (const octave_value& v) { return v.iscell (); } #endif } } #endif signal-1.4.5/src/remez.cc0000644000000000000000000006001314456505401013410 0ustar0000000000000000/* Copyright (C) 1995, 1998 Jake Janovetz Copyright (C) 1999 Paul Kienzle Copyright (C) 2000 Kai Habel This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, see . */ /************************************************************************** * There appear to be some problems with the routine Search. See comments * therein [search for PAK:]. I haven't looked closely at the rest * of the code---it may also have some problems. *************************************************************************/ #include #include #ifndef OCTAVE_LOCAL_BUFFER #include #define OCTAVE_LOCAL_BUFFER(T, buf, size) \ std::vector buf ## _vector (size); \ T *buf = &(buf ## _vector[0]) #endif #include "octave-compat.h" #define CONST const #define BANDPASS 1 #define DIFFERENTIATOR 2 #define HILBERT 3 #define NEGATIVE 0 #define POSITIVE 1 #define Pi 3.1415926535897932 #define Pi2 6.2831853071795865 #define GRIDDENSITY 16 #define MAXITERATIONS 40 /******************* * CreateDenseGrid *================= * Creates the dense grid of frequencies from the specified bands. * Also creates the Desired Frequency Response function (D[]) and * the Weight function (W[]) on that dense grid * * * INPUT: * ------ * int r - 1/2 the number of filter coefficients * int numtaps - Number of taps in the resulting filter * int numband - Number of bands in user specification * double bands[] - User-specified band edges [2*numband] * double des[] - Desired response per band [2*numband] * double weight[] - Weight per band [numband] * int symmetry - Symmetry of filter - used for grid check * int griddensity * * OUTPUT: * ------- * int gridsize - Number of elements in the dense frequency grid * double Grid[] - Frequencies (0 to 0.5) on the dense grid [gridsize] * double D[] - Desired response on the dense grid [gridsize] * double W[] - Weight function on the dense grid [gridsize] *******************/ void CreateDenseGrid(int r, int numtaps, int numband, const double bands[], const double des[], const double weight[], int gridsize, double Grid[], double D[], double W[], int symmetry, int griddensity) { int i, j, k, band; double delf, lowf, highf, grid0; delf = 0.5/(griddensity*r); /* * For differentiator, hilbert, * symmetry is odd and Grid[0] = max(delf, bands[0]) */ grid0 = (symmetry == NEGATIVE) && (delf > bands[0]) ? delf : bands[0]; j=0; for (band=0; band < numband; band++) { lowf = (band==0 ? grid0 : bands[2*band]); highf = bands[2*band + 1]; k = (int)((highf - lowf)/delf + 0.5); /* .5 for rounding */ if (band == 0 && symmetry == NEGATIVE) k--; for (i=0; i (0.5 - delf)) && (numtaps % 2)) { Grid[gridsize-1] = 0.5-delf; } } /******************** * InitialGuess *============== * Places Extremal Frequencies evenly throughout the dense grid. * * * INPUT: * ------ * int r - 1/2 the number of filter coefficients * int gridsize - Number of elements in the dense frequency grid * * OUTPUT: * ------- * int Ext[] - Extremal indexes to dense frequency grid [r+1] ********************/ void InitialGuess(int r, int Ext[], int gridsize) { int i; for (i=0; i<=r; i++) Ext[i] = i * (gridsize-1) / r; } /*********************** * CalcParms *=========== * * * INPUT: * ------ * int r - 1/2 the number of filter coefficients * int Ext[] - Extremal indexes to dense frequency grid [r+1] * double Grid[] - Frequencies (0 to 0.5) on the dense grid [gridsize] * double D[] - Desired response on the dense grid [gridsize] * double W[] - Weight function on the dense grid [gridsize] * * OUTPUT: * ------- * double ad[] - 'b' in Oppenheim & Schafer [r+1] * double x[] - [r+1] * double y[] - 'C' in Oppenheim & Schafer [r+1] ***********************/ void CalcParms(int r, int Ext[], double Grid[], double D[], double W[], double ad[], double x[], double y[]) { int i, j, k, ld; double sign, xi, delta, denom, numer; /* * Find x[] */ for (i=0; i<=r; i++) x[i] = cos(Pi2 * Grid[Ext[i]]); /* * Calculate ad[] - Oppenheim & Schafer eq 7.132 */ ld = (r-1)/15 + 1; /* Skips around to avoid round errors */ for (i=0; i<=r; i++) { denom = 1.0; xi = x[i]; for (j=0; j0.0) && (E[0]>E[1])) || ((E[0]<0.0) && (E[0]=E[i-1]) && (E[i]>E[i+1]) && (E[i]>0.0)) || ((E[i]<=E[i-1]) && (E[i]= 2*r) return -3; foundExt[k++] = i; } } /* * Check for extremum at 0.5 */ j = gridsize-1; if (((E[j]>0.0) && (E[j]>E[j-1])) || ((E[j]<0.0) && (E[j]= 2*r) return -3; foundExt[k++] = j; } // PAK: we sometimes get not enough extremal frequencies if (k < r+1) return -2; /* * Remove extra extremals */ extra = k - (r+1); assert(extra >= 0); while (extra > 0) { if (E[foundExt[0]] > 0.0) up = 1; /* first one is a maxima */ else up = 0; /* first one is a minima */ l=0; alt = 1; for (j=1; j 0.0)) up = 1; /* switch to a maxima */ else { alt = 0; // PAK: break now and you will delete the smallest overall // extremal. If you want to delete the smallest of the // pair of non-alternating extremals, then you must do: // // if (fabs(E[foundExt[j]]) < fabs(E[foundExt[j-1]])) l=j; // else l=j-1; break; /* Ooops, found two non-alternating */ } /* extrema. Delete smallest of them */ } /* if the loop finishes, all extrema are alternating */ /* * If there's only one extremal and all are alternating, * delete the smallest of the first/last extremals. */ if ((alt) && (extra == 1)) { if (fabs(E[foundExt[k-1]]) < fabs(E[foundExt[0]])) /* Delete last extremal */ l = k-1; // PAK: changed from l = foundExt[k-1]; else /* Delete first extremal */ l = 0; // PAK: changed from l = foundExt[0]; } for (j=l; j max) max = current; } return (((max-min)/max) < 0.0001); } /******************** * remez *======= * Calculates the optimal (in the Chebyshev/minimax sense) * FIR filter impulse response given a set of band edges, * the desired response on those bands, and the weight given to * the error in those bands. * * INPUT: * ------ * int numtaps - Number of filter coefficients * int numband - Number of bands in filter specification * double bands[] - User-specified band edges [2 * numband] * double des[] - User-specified band responses [numband] * double weight[] - User-specified error weights [numband] * int type - Type of filter * * OUTPUT: * ------- * double h[] - Impulse response of final filter [numtaps] * returns - true on success, false on failure to converge ********************/ int remez(double h[], int numtaps, int numband, const double bands[], const double des[], const double weight[], int type, int griddensity) { double *Grid, *W, *D, *E; int i, iter, gridsize, r, *Ext; double *taps, c; double *x, *y, *ad; int symmetry; if (type == BANDPASS) symmetry = POSITIVE; else symmetry = NEGATIVE; r = numtaps/2; /* number of extrema */ if ((numtaps%2) && (symmetry == POSITIVE)) r++; /* * Predict dense grid size in advance for memory allocation * .5 is so we round up, not truncate */ gridsize = 0; for (i=0; i 0.0001) W[i] = W[i]/Grid[i]; } } /* * For odd or Negative symmetry filters, alter the * D[] and W[] according to Parks McClellan */ if (symmetry == POSITIVE) { if (numtaps % 2 == 0) { for (i=0; i 6) { print_usage (); return retval; } int numtaps = octave::math::nint (args(0).double_value ()) + 1; if (numtaps < 4) { error("remez: number of taps must be an integer greater than 3"); return retval; } ColumnVector o_bands(args(1).vector_value()); int numbands = o_bands.numel()/2; OCTAVE_LOCAL_BUFFER(double, bands, numbands*2); if (numbands < 1 || o_bands.numel()%2 == 1) { error("remez: must have an even number of band edges"); return retval; } for (i=1; i < o_bands.numel(); i++) { if (o_bands(i) 1) { error("band edges must be in the range [0,1]"); return retval; } for(i=0; i < 2*numbands; i++) bands[i] = o_bands(i)/2.0; ColumnVector o_response(args(2).vector_value()); OCTAVE_LOCAL_BUFFER (double, response, numbands*2); if (o_response.numel() != o_bands.numel()) { error("remez: must have one response magnitude for each band edge"); return retval; } for(i=0; i < 2*numbands; i++) response[i] = o_response(i); std::string stype = std::string("bandpass"); int density = 16; OCTAVE_LOCAL_BUFFER (double, weight, numbands); for (i=0; i < numbands; i++) weight[i] = 1.0; if (nargin > 3) { if (args(3).is_string()) stype = args(3).string_value(); else if (args(3).is_real_matrix() || args(3).is_real_scalar()) { ColumnVector o_weight(args(3).vector_value()); if (o_weight.numel() != numbands) { error("remez: need one weight for each band [=length(band)/2]"); return retval; } for (i=0; i < numbands; i++) weight[i] = o_weight(i); } else { error("remez: incorrect argument list"); return retval; } } if (nargin > 4) { if (args(4).is_string() && !args(3).is_string()) stype = args(4).string_value(); else if (args(4).is_real_scalar()) density = octave::math::nint (args(4).double_value ()); else { error("remez: incorrect argument list"); return retval; } } if (nargin > 5) { if (args(5).is_real_scalar() && !args(4).is_real_scalar()) density = octave::math::nint (args(5).double_value ()); else { error("remez: incorrect argument list"); return retval; } } int itype; if (stype == "bandpass") itype = BANDPASS; else if (stype == "differentiator") itype = DIFFERENTIATOR; else if (stype == "hilbert") itype = HILBERT; else { error("remez: unknown ftype '%s'", stype.data()); return retval; } if (density < 16) { error("remez: griddensity is too low; must be greater than 16"); return retval; } OCTAVE_LOCAL_BUFFER (double, coeff, numtaps+5); int err = remez(coeff,numtaps,numbands,bands,response,weight,itype,density); if (err == -1) warning("remez: -- failed to converge -- returned filter may be bad."); else if (err == -2) { error("remez: insufficient extremals--cannot continue"); return retval; } else if (err == -3) { error("remez: too many extremals--cannot continue"); return retval; } ColumnVector h(numtaps); while(numtaps--) h(numtaps) = coeff[numtaps]; return octave_value(h); } /* %!test %! b = [ %! 0.0415131831103279 %! 0.0581639884202646 %! -0.0281579212691008 %! -0.0535575358002337 %! -0.0617245915143180 %! 0.0507753178978075 %! 0.2079018331396460 %! 0.3327160895375440 %! 0.3327160895375440 %! 0.2079018331396460 %! 0.0507753178978075 %! -0.0617245915143180 %! -0.0535575358002337 %! -0.0281579212691008 %! 0.0581639884202646 %! 0.0415131831103279]; %! assert(remez(15,[0,0.3,0.4,1],[1,1,0,0]),b,1e-14); */ signal-1.4.5/src/sosfilt.cc0000644000000000000000000000532214456505401013753 0ustar0000000000000000/* Copyright (C) 2008 Eric Chassande-Mottin, CNRS (France) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, see . */ #include #include #include #include #include #include #include "octave-compat.h" DEFUN_DLD (sosfilt, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{y} =} sosfilt (@var{sos}, @var{x})\n\ Second order section IIR filtering of @var{x}. The second order section\n\ filter is described by the matrix @var{sos} with:\n\ \n\ @multitable {col 1} {this is column two}\n\ @item @tab [ @var{B1} @var{A1} ]@*\n\ @item @var{sos} = @tab [ @dots{} ],@*\n\ @item @tab [ @var{BN} @var{AN} ]@*\n\ @end multitable\n\ \n\ where @code{@var{B1} = [b0 b1 b2]} and @code{@var{A1} = [1 a1 a2]} for\n\ section 1, etc. The b0 entry must be nonzero for each section.\n\ @end deftypefn\n") { octave_value_list retval; int nargin = args.length (); if (nargin != 2) { print_usage (); return retval; } Matrix sos( args(0).matrix_value() ); if (sos.columns() != 6) { error("Second-order section matrix must be a non-empty Lx6 matrix"); return retval; } Matrix x( args(1).matrix_value() ); int n=x.rows(); int m=x.columns(); bool isrowvector=false; if ((n==1)&&(m>1)) // if row vector, transpose to column vector { x=x.transpose(); n=x.rows(); m=x.columns(); isrowvector=true; } Matrix y(n,m,0.0); for (int k=0; k This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, see . */ #include #include #include #include #include #include #include "octave-compat.h" template MT upfirdn (MT &x, ColumnVector &h, octave_idx_type p, octave_idx_type q) { octave_idx_type rx = x.rows (); octave_idx_type cx = x.columns (); bool isrowvector = false; if ((rx == 1) && (cx > 1)) // if row vector, transpose to column vector { x = x.transpose (); rx = x.rows (); cx = x.columns (); isrowvector = true; } octave_idx_type Lh = h.numel (); const octave_idx_type Ly = ceil (static_cast ((rx-1)*p + Lh) / static_cast (q)); MT y (Ly, cx, 0.0); octave_idx_type zero = 0; for (octave_idx_type c = 0; c < cx; c++) for (octave_idx_type m = 0; m < Ly; m++) { const octave_idx_type n = (m * q) / p; const octave_idx_type lm = (m * q) % p; y (m,c) = 0.0; for (octave_idx_type k = std::max (zero, n-rx+1); k <= n && k*p + lm < Lh; k++) y (m,c) += h (k*p + lm) * x (n-k, c); } if (isrowvector) y = y.transpose (); return y; } DEFUN_DLD (upfirdn, args,, "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{y} =} upfirdn (@var{x}, @var{h}, @var{p}, @var{q})\n\ Upsample, FIR filtering, and downsample.\n\ @end deftypefn\n") { octave_value_list retval; const int nargin = args.length (); if (nargin != 4) { print_usage (); return retval; } ColumnVector h (args (1).vector_value ()); octave_idx_type p = args (2).idx_type_value (); octave_idx_type q = args (3).idx_type_value (); // Do the dispatching if (octave::signal::isreal (args (0))) { Matrix x = args (0).matrix_value (); Matrix y = upfirdn (x, h, p, q); retval (0) = y; } else if (octave::signal::iscomplex (args (0))) { ComplexMatrix x = args (0).complex_matrix_value (); ComplexMatrix y = upfirdn (x, h, p, q); retval (0) = y; } else { err_wrong_type_arg ("upfirdn", args(0)); return retval; } return retval; } /* %!assert (isequal (upfirdn (1:100, 1, 1, 1), 1:100)) %!assert (isequal (upfirdn (1:100, 1, 1, 2), 1:2:100)) %% Test input validation %!error upfirdn () %!error upfirdn (1,2) %!error upfirdn (1,2,3) %!error upfirdn (1,2,3,4,5) */