signal-1.4.1/0000755000000000000000000000000013427376005011167 5ustar0000000000000000signal-1.4.1/COPYING0000644000000000000000000010451513427376005012230 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.1/DESCRIPTION0000644000000000000000000000055213427376005012677 0ustar0000000000000000Name: signal Version: 1.4.1 Date: 2019-02-08 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.1/INDEX0000644000000000000000000000355013427376005011764 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 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 freqs freqs_plot fwhm grpdelay impz zplane Filter Conversion polystab residued residuez 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 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 Sample Rate Change data2fun decimate downsample interp resample upfirdn upsample Utility buffer clustersegment fracshift marcumq primitive sampled2continuous schtrig upsamplefill wkeep wrev zerocrossing signal-1.4.1/NEWS0000644000000000000000000001705113427376005011672 0ustar0000000000000000Summary 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.1/inst/0000755000000000000000000000000013427376005012144 5ustar0000000000000000signal-1.4.1/inst/__power.m0000644000000000000000000000610513427376005013756 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.1/inst/ar_psd.m0000644000000000000000000002717113427376005013602 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.1/inst/arburg.m0000644000000000000000000002272513427376005013614 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.1/inst/aryule.m0000644000000000000000000000470313427376005013627 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.1/inst/besselap.m0000644000000000000000000000313713427376005014124 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.1/inst/besself.m0000644000000000000000000001034213427376005013745 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.1/inst/bilinear.m0000644000000000000000000001113413427376005014107 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.1/inst/bitrevorder.m0000644000000000000000000000370313427376005014654 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.1/inst/blackmanharris.m0000644000000000000000000000516713427376005015314 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.1/inst/blackmannuttall.m0000644000000000000000000000523013427376005015476 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.1/inst/bohmanwin.m0000644000000000000000000000303013427376005014300 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.1/inst/boxcar.m0000644000000000000000000000250313427376005013600 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.1/inst/buffer.m0000644000000000000000000002020413427376005013571 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{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.1/inst/buttap.m0000644000000000000000000000241113427376005013617 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.1/inst/butter.m0000644000000000000000000002233113427376005013630 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.1/inst/buttord.m0000644000000000000000000011610613427376005014012 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.1/inst/cceps.m0000644000000000000000000000435613427376005013427 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.1/inst/cconv.m0000644000000000000000000000701213427376005013432 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.1/inst/cheb.m0000644000000000000000000000327613427376005013233 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.1/inst/cheb1ap.m0000644000000000000000000000263613427376005013634 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.1/inst/cheb1ord.m0000644000000000000000000010704513427376005014020 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.1/inst/cheb2ap.m0000644000000000000000000000263713427376005013636 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")}. ## ## @seealso{cheby2} ## @end deftypefn function [z, p, g] = cheb2ap (n, Rp) 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 signal-1.4.1/inst/cheb2ord.m0000644000000000000000000010703313427376005014016 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.1/inst/chebwin.m0000644000000000000000000000640313427376005013744 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.1/inst/cheby1.m0000644000000000000000000001274013427376005013501 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.1/inst/cheby2.m0000644000000000000000000001362713427376005013507 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.1/inst/chirp.m0000644000000000000000000001233713427376005013435 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.1/inst/clustersegment.m0000644000000000000000000000510213427376005015364 0ustar0000000000000000## Copyright (C) 2010 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.1/inst/cmorwavf.m0000644000000000000000000000227013427376005014147 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.1/inst/cohere.m0000644000000000000000000000373413427376005013576 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 ## . ## Usage: ## [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. ## 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.1/inst/convmtx.m0000644000000000000000000000345613427376005014030 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.1/inst/cplxreal.m0000644000000000000000000000642713427376005014145 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) && ((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 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.1/inst/cpsd.m0000644000000000000000000000450213427376005013254 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.1/inst/csd.m0000644000000000000000000000367513427376005013106 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 ## . ## Usage: ## [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. 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.1/inst/czt.m0000644000000000000000000000660013427376005013124 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.1/inst/data2fun.m0000644000000000000000000001203713427376005014031 0ustar0000000000000000## 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{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 %! [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"]); %! end_unwind_protect %!test %! unwind_protect %! [fhandle fname] = data2fun (t, y, "file", ""); %! yt = testdata2fun (t); %! assert (y, yt); %! assert (y, fhandle (t)); %! unwind_protect_cleanup %! unlink (fname); %! unlink ([fname(1:end-2) ".mat"]); %! end_unwind_protect %!test %! unwind_protect %! [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"]); %! end_unwind_protect ## Test input validation %!error data2fun () %!error data2fun (1) %!error data2fun (1, 2, "file") signal-1.4.1/inst/db2pow.m0000644000000000000000000000314113427376005013516 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.10000 1.00000 10.00000 ## @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.1/inst/dct.m0000644000000000000000000000564313427376005013104 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.1/inst/dct2.m0000644000000000000000000000267213427376005013165 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.1/inst/dctmtx.m0000644000000000000000000000337013427376005013630 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.1/inst/decimate.m0000644000000000000000000000770713427376005014110 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.1/inst/dftmtx.m0000644000000000000000000000262513427376005013635 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.1/inst/digitrevorder.m0000644000000000000000000000505713427376005015202 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.1/inst/diric.m0000644000000000000000000000225013427376005013413 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.1/inst/downsample.m0000644000000000000000000000250413427376005014474 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.1/inst/dst.m0000644000000000000000000000266413427376005013124 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.1/inst/dwt.m0000644000000000000000000000357713427376005013134 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.1/inst/ellip.m0000644000000000000000000001335613427376005013437 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.1/inst/ellipap.m0000644000000000000000000000314113427376005013747 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.1/inst/ellipord.m0000644000000000000000000010273313427376005014142 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.1/inst/fht.m0000644000000000000000000000417213427376005013107 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.1/inst/filtfilt.m0000644000000000000000000001055213427376005014142 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.1/inst/filtic.m0000644000000000000000000000753113427376005013602 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.1/inst/findpeaks.m0000644000000000000000000003171113427376005014271 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(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 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.1/inst/fir1.m0000644000000000000000000001555313427376005013174 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.1/inst/fir2.m0000644000000000000000000002070513427376005013170 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 ## 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) %!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.1/inst/firls.m0000644000000000000000000001052213427376005013441 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.1/inst/flattopwin.m0000644000000000000000000000445413427376005014520 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.1/inst/fracshift.m0000644000000000000000000001414513427376005014300 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.1/inst/freqs.m0000644000000000000000000000273413427376005013450 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.1/inst/freqs_plot.m0000644000000000000000000000276213427376005014507 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.1/inst/fwhm.m0000644000000000000000000001277613427376005013300 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.1/inst/fwht.m0000644000000000000000000000542313427376005013276 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.1/inst/gauspuls.m0000644000000000000000000000430413427376005014166 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.1/inst/gaussian.m0000644000000000000000000000351513427376005014140 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.1/inst/gausswin.m0000644000000000000000000000353613427376005014171 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.1/inst/gmonopuls.m0000644000000000000000000000211313427376005014342 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.1/inst/grpdelay.m0000644000000000000000000002740013427376005014134 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.1/inst/hann.m0000644000000000000000000000402313427376005013245 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.1/inst/hilbert.m0000644000000000000000000000755713427376005013771 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.1/inst/idct.m0000644000000000000000000000501113427376005013242 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.1/inst/idct2.m0000644000000000000000000000274713427376005013341 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.1/inst/idst.m0000644000000000000000000000147013427376005013267 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.1/inst/ifht.m0000644000000000000000000000402613427376005013256 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.1/inst/ifwht.m0000644000000000000000000000472013427376005013446 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.1/inst/iirlp2mb.m0000644000000000000000000002754413427376005014056 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.1/inst/impinvar.m0000644000000000000000000001276513427376005014162 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.1/inst/interp.m0000644000000000000000000000457213427376005013633 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.1/inst/invfreq.m0000644000000000000000000002136613427376005014004 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 ## . ## usage: [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 ## 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.1/inst/invfreqs.m0000644000000000000000000000631713427376005014166 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 ## . ## Usage: [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)); ## 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.1/inst/invfreqz.m0000644000000000000000000000607713427376005014200 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 ## . ## usage: [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))); ## 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.1/inst/invimpinvar.m0000644000000000000000000001266013427376005014671 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.1/inst/kaiser.m0000644000000000000000000000431313427376005013601 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.1/inst/kaiserord.m0000644000000000000000000001341013427376005014304 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.1/inst/levinson.m0000644000000000000000000000644113427376005014164 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.1/inst/marcumq.m0000644000000000000000000004501713427376005013776 0ustar0000000000000000## Copyright (C) 2012 Robert T. Short ## ## 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.1/inst/mexihat.m0000644000000000000000000000217413427376005013765 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.1/inst/meyeraux.m0000644000000000000000000000176513427376005014172 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.1/inst/morlet.m0000644000000000000000000000213613427376005013626 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.1/inst/movingrms.m0000644000000000000000000000554313427376005014352 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.1/inst/mscohere.m0000644000000000000000000000455713427376005014142 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.1/inst/ncauer.m0000644000000000000000000000646513427376005013612 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 ## . ## usage: [Zz, Zp, Zg] = ncauer(Rp, Rs, n) ## ## Analog prototype for Cauer filter. ## [z, p, g]=ncauer(Rp, Rs, ws) ## Rp = Passband ripple ## Rs = Stopband ripple ## Ws = Desired order ## ## 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. 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.1/inst/nuttallwin.m0000644000000000000000000000507413427376005014531 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.1/inst/parzenwin.m0000644000000000000000000000312513427376005014340 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.1/inst/pburg.m0000644000000000000000000001406613427376005013450 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 ## . ## usage: ## [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". 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.1/inst/peak2peak.m0000644000000000000000000000546413427376005014176 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.1/inst/peak2rms.m0000644000000000000000000000351013427376005014045 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.1/inst/pei_tseng_notch.m0000644000000000000000000001043313427376005015473 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.1/inst/polystab.m0000644000000000000000000000204313427376005014156 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.1/inst/pow2db.m0000644000000000000000000000341513427376005013522 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.1/inst/primitive.m0000644000000000000000000000470313427376005014336 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.1/inst/private/0000755000000000000000000000000013427376005013616 5ustar0000000000000000signal-1.4.1/inst/private/__fwht_opts__.m0000644000000000000000000000450613427376005016612 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.1/inst/private/h1_z_deriv.m0000644000000000000000000000462013427376005016030 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.1/inst/private/inv_residue.m0000644000000000000000000000446513427376005016321 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.1/inst/private/to_real.m0000644000000000000000000000221613427376005015422 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.1/inst/private/validate_filter_bands.m0000644000000000000000000000524213427376005020304 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.1/inst/pulstran.m0000644000000000000000000001407413427376005014200 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.1/inst/pwelch.m0000644000000000000000000011463713427376005013620 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 ## . ## USAGE: ## [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. 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.1/inst/pyulear.m0000644000000000000000000001160113427376005014002 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 ## . ## usage: ## [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". 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.1/inst/qp_kaiser.m0000644000000000000000000000552613427376005014310 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.1/inst/rceps.m0000644000000000000000000001131713427376005013441 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.1/inst/rectpuls.m0000644000000000000000000000463313427376005014171 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.1/inst/rectwin.m0000644000000000000000000000260013427376005013773 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.1/inst/resample.m0000644000000000000000000001236513427376005014141 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); if f, f = conj(fliplr(f)); endif 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); signal-1.4.1/inst/rms.m0000644000000000000000000000344213427376005013126 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.1/inst/rssq.m0000644000000000000000000000337013427376005013315 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.1/inst/sampled2continuous.m0000644000000000000000000000271213427376005016162 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.1/inst/sawtooth.m0000644000000000000000000000401213427376005014167 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.1/inst/schtrig.m0000644000000000000000000001007013427376005013763 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.1/inst/sftrans.m0000644000000000000000000001727413427376005014015 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.1/inst/sgolay.m0000644000000000000000000001042613427376005013623 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.1/inst/sgolayfilt.m0000644000000000000000000001161313427376005014501 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.1/inst/shanwavf.m0000644000000000000000000000240713427376005014142 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.1/inst/shiftdata.m0000644000000000000000000000457013427376005014277 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.1/inst/sigmoid_train.m0000644000000000000000000001135213427376005015154 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.1/inst/sos2tf.m0000644000000000000000000000621613427376005013547 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{b}, @var{a}] =} sos2tf (@var{sos}) ## @deftypefnx {Function File} {[@var{b}, @var{a}] =} sos2tf (@var{sos}, @var{g}) ## Convert series second-order sections to direct form @math{H(z) = B(z)/A(z)}. ## ## 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}.' = [1 a1 a2]} for ## section 1, etc. The b0 entry must be nonzero for each section. ## 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 digital filter @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 nB = length(B); while nB && B(nB)==0 B=B(1:nB-1); nB=length(B); endwhile nA = length(A); while nA && A(nA)==0 A=A(1:nA-1); nA=length(A); 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); signal-1.4.1/inst/sos2zp.m0000644000000000000000000000633113427376005013565 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{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}.' = [1 a1 a2]} for ## section 1, etc. The b0 entry must be nonzero for each section. ## 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.90000 + 0.00000i ## 0.90000 + 0.00000i ## -0.00000 + 0.70000i ## 0.00000 - 0.70000i ## @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 gains = sos(:,1); # All b0 coeffs k = prod(gains)*g; # pole-zero gain if k==0, error('sos2zp: one or more section gains is zero'); endif sos(:,1:3) = sos(:,1:3)./ [gains gains gains]; [N,m] = size(sos); if m~=6, error('sos2zp: sos matrix should be N by 6'); endif z = zeros(2*N,1); p = zeros(2*N,1); for i=1:N ndx = [2*i-1:2*i]; zi = roots(sos(i,1:3)); z(ndx) = zi; pi = roots(sos(i,4:6)); p(ndx) = pi; 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); signal-1.4.1/inst/specgram.m0000644000000000000000000002231413427376005014125 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.1/inst/ss2tf.m0000644000000000000000000000334213427376005013365 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.1/inst/ss2zp.m0000644000000000000000000000235013427376005013403 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{p}, @var{z}, @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.1/inst/tf2sos.m0000644000000000000000000000475313427376005013553 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.1/inst/tf2ss.m0000644000000000000000000000354513427376005013372 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.1/inst/tf2zp.m0000644000000000000000000000251613427376005013373 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.1/inst/tfe.m0000644000000000000000000000373313427376005013106 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 ## . ## Usage: ## [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. 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.1/inst/tfestimate.m0000644000000000000000000000452313427376005014473 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.1/inst/triang.m0000644000000000000000000000472313427376005013614 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.1/inst/tripuls.m0000644000000000000000000000677013427376005014036 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.1/inst/tukeywin.m0000644000000000000000000000522413427376005014204 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.1/inst/udecode.m0000644000000000000000000000714113427376005013735 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.1/inst/uencode.m0000644000000000000000000000502013427376005013741 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.1/inst/ultrwin.m0000644000000000000000000002025713427376005014034 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.1/inst/unshiftdata.m0000644000000000000000000000431013427376005014632 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.1/inst/upsample.m0000644000000000000000000000242213427376005014150 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.1/inst/upsamplefill.m0000644000000000000000000000537413427376005015030 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.1/inst/wconv.m0000644000000000000000000000341213427376005013456 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.1/inst/welchwin.m0000644000000000000000000000735113427376005014150 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.1/inst/window.m0000644000000000000000000000321313427376005013630 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.1/inst/wkeep.m0000644000000000000000000000362313427376005013441 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.1/inst/wrev.m0000644000000000000000000000213413427376005013305 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.1/inst/xcorr.m0000644000000000000000000002572413427376005013471 0ustar0000000000000000## Copyright (C) 1999-2001 Paul Kienzle ## Copyright (C) 2004 ## Copyright (C) 2008, 2010 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{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 ## 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, Y, maxlag, scale) if (nargin < 1 || nargin > 4) print_usage; endif ## assign arguments that are missing from the list ## or reassign (right shift) them according to data type 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 ## 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) || ischar(Y) || ! 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') ## 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 ##-------------------------------------------------------------- signal-1.4.1/inst/xcorr2.m0000644000000000000000000001132313427376005013541 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.1/inst/xcov.m0000644000000000000000000000467413427376005013314 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 signal-1.4.1/inst/zerocrossing.m0000644000000000000000000000433413427376005015055 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.1/inst/zp2sos.m0000644000000000000000000001043313427376005013563 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}] =} 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}.' = [1 a1 a2]} for ## section 1, etc. The b0 entry must be nonzero for each section. ## 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{sos2pz, sos2tf, tf2sos, zp2tf, tf2zp} ## @end deftypefn function [sos,g] = zp2sos(z,p,k) if nargin<3, k=1; endif if nargin<2, p=[]; endif [zc,zr] = cplxreal(z(:)); [pc,pr] = cplxreal(p(:)); ## zc,zr,pc,pr nzc=length(zc); npc=length(pc); nzr=length(zr); npr=length(pr); ## Pair up real zeros: if nzr if mod(nzr,2)==1, zr=[zr;0]; nzr=nzr+1; endif nzrsec = nzr/2; zrms = -zr(1:2:nzr-1)-zr(2:2:nzr); zrp = zr(1:2:nzr-1).*zr(2:2:nzr); else nzrsec = 0; endif ## Pair up real poles: if npr if mod(npr,2)==1, pr=[pr;0]; npr=npr+1; endif nprsec = npr/2; prms = -pr(1:2:npr-1)-pr(2:2:npr); prp = pr(1:2:npr-1).*pr(2:2:npr); else nprsec = 0; endif nsecs = max(nzc+nzrsec,npc+nprsec); ## Convert complex zeros and poles to real 2nd-order section form: zcm2r = -2*real(zc); zca2 = abs(zc).^2; pcm2r = -2*real(pc); pca2 = abs(pc).^2; sos = zeros(nsecs,6); sos(:,1) = ones(nsecs,1); # all 2nd-order polynomials are monic sos(:,4) = ones(nsecs,1); nzrl=nzc+nzrsec; # index of last real zero section nprl=npc+nprsec; # index of last real pole section for i=1:nsecs if i<=nzc # lay down a complex zero pair: sos(i,2:3) = [zcm2r(i) zca2(i)]; elseif i<=nzrl # lay down a pair of real zeros: sos(i,2:3) = [zrms(i-nzc) zrp(i-nzc)]; endif if i<=npc # lay down a complex pole pair: sos(i,5:6) = [pcm2r(i) pca2(i)]; elseif i<=nprl # lay down a pair of real poles: sos(i,5:6) = [prms(i-npc) prp(i-npc)]; endif endfor ## If no output argument for the overall gain, combine it into the ## first section. if (nargout < 2) sos(1,1:3) *= k; else g = k; endif endfunction %!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); signal-1.4.1/inst/zp2ss.m0000644000000000000000000000352613427376005013411 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.1/inst/zp2tf.m0000644000000000000000000000272713427376005013377 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.1/inst/zplane.m0000644000000000000000000001254313427376005013620 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.1/io.sourceforge.octave.signal.metainfo.xml0000644000000000000000000000240213427376005021175 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.1/src/0000755000000000000000000000000013427376005011756 5ustar0000000000000000signal-1.4.1/src/Makefile0000644000000000000000000000270413427376005013421 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 -Wno-deprecated-declarations $(PKG_CXXFLAGS_APPEND) OCT_FILES = \ __fwht__.oct \ __ultrwin__.oct \ cl2bp.oct \ medfilt1.oct \ remez.oct \ sosfilt.oct \ upfirdn.oct CL2BP_OBJECTS = cl2bp.o cl2bp_lib.o OCT_SOURCES = $(patsubst %.oct,%.cc,$(OCT_FILES)) all: $(OCT_FILES) %.o: %.cc $(MKOCTFILE) $(PKG_CXXFLAGS) -c $< -o $@ %.oct: %.cc octave-compat.h $(MKOCTFILE) $(PKG_CXXFLAGS) $< -o $@ cl2bp.oct: $(CL2BP_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.1/src/__fwht__.cc0000644000000000000000000000331013427376005014026 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.1/src/__ultrwin__.cc0000644000000000000000000002222413427376005014567 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.1/src/cl2bp.cc0000644000000000000000000001143013427376005013266 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); if (error_state) { err_wrong_type_arg ("cl2bp", args(0)); return retval; } const double w1 = args(1).double_value(); if (error_state) { err_wrong_type_arg ("cl2bp", args(1)); return retval; } const double w2 = args(2).double_value(); if (error_state) { err_wrong_type_arg ("cl2bp", args(2)); return retval; } const ColumnVector up_vector(args(3).vector_value()); if (error_state) { err_wrong_type_arg ("cl2bp", args(3)); return retval; } const ColumnVector lo_vector(args(4).vector_value()); if (error_state) { err_wrong_type_arg ("cl2bp", args(4)); return retval; } 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 (error_state) { err_wrong_type_arg ("cl2bp", args(5)); return retval; } 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.1/src/cl2bp_lib.h0000644000000000000000000000731513427376005013765 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.1/src/medfilt1.cc0000644000000000000000000004061213427376005013775 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.1/src/octave-compat.h0000644000000000000000000000444213427376005014675 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 (); } #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 (); } #endif } } #endif signal-1.4.1/src/remez.cc0000644000000000000000000005776513427376005013433 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.1/src/sosfilt.cc0000644000000000000000000000563213427376005013756 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 (error_state) { err_wrong_type_arg ("sosfilt", args(0)); return retval; } if (sos.columns() != 6) { error("Second-order section matrix must be a non-empty Lx6 matrix"); return retval; } Matrix x( args(1).matrix_value() ); if (error_state) { err_wrong_type_arg ("sosfilt", args(1)); return retval; } 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 double r = p/(static_cast (q)); const octave_idx_type Ly = ceil (static_cast ((rx-1)*p + Lh) / static_cast (q)); MT y (Ly, cx, 0.0); for (octave_idx_type c = 0; c < cx; c++) { octave_idx_type m = 0; while (m < Ly) { const octave_idx_type n = floor (m/r); const octave_idx_type lm = (m * q) % p; octave_idx_type k = 0; typename MT::element_type accum; accum = 0.0; do { octave_idx_type ix = n - k; if (ix >= rx) { k ++; continue; } const octave_idx_type ih = k * p + lm; if ((ih >= Lh) | (ix < 0)) break; accum += h (ih) * x (ix, c); k++; } while (1); y (m, c) = accum; m ++; } } 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 ()); if (error_state) { err_wrong_type_arg ("upfirdn", args(1)); return retval; } octave_idx_type p = args (2).idx_type_value (); if (error_state) { err_wrong_type_arg ("upfirdn", args(2)); return retval; } octave_idx_type q = args (3).idx_type_value (); if (error_state) { err_wrong_type_arg ("upfirdn", args(3)); return retval; } // Do the dispatching if (octave::signal::isreal (args (0))) { Matrix x = args (0).matrix_value (); if (error_state) { err_wrong_type_arg ("upfirdn", args(0)); return retval; } Matrix y = upfirdn (x, h, p, q); retval (0) = y; } else if (octave::signal::iscomplex (args (0))) { ComplexMatrix x = args (0).complex_matrix_value (); if (error_state) { err_wrong_type_arg ("upfirdn", args(0)); return retval; } 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) */