signal/COPYING0000644000000000000000000010451312124117010011505 0ustar 00000000000000 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/DESCRIPTION0000644000000000000000000000076512124117010012164 0ustar 00000000000000Name: Signal Version: 1.2.2 Date: 2013-03-25 Author: various authors Maintainer: Octave-Forge community Title: Signal Processing. Description: Signal processing tools, including filtering, windowing and display functions. Depends: octave (>= 3.6.0), specfun, control (>= 2.2.3), general (>= 1.3.2) ## depends on specfun because of ellipke. When it moves to octave core, dependency can be removed Autoload: no License: GPLv3+, public domain Url: http://octave.sf.net signal/INDEX0000644000000000000000000000277312124117010011251 0ustar 00000000000000signal >> Signal processing Signals diric gauspuls gmonopuls pulstran tripuls rectpuls sawtooth square chirp specgram buffer mexihat meyeraux morlet shanwavf cmorwavf sigmoid_train Filtering filtfilt filtic sgolayfilt sosfilt medfilt1 movingrms Filter analysis freqs freqs_plot grpdelay impz zplane fwhm Filter conversion convmtx residuez residued sos2tf sos2zp ss2tf ss2zp tf2sos tf2ss tf2zp zp2sos zp2ss zp2tf polystab IIR Filter design besself buttap butter cheb cheb1ap cheb2ap cheby1 cheby2 ellipap ellip ncauer buttord cheb1ord cheb2ord ellipord besselap sftrans bilinear impinvar invimpinvar iirlp2mb pei_tseng_notch FIR filter design fir1 fir2 firls kaiserord remez sgolay qp_kaiser cl2bp Transforms czt dctmtx dct2 idct2 dct idct dst idst dftmtx hilbert rceps cceps cplxreal bitrevorder dwt fht ifht fwht ifwht Power spectrum analysis pwelch tfe tfestimate cohere csd ar_psd cpsd mscohere pburg pyulear xcorr xcorr2 xcov __power Window functions window barthannwin blackmanharris blackmannuttall bohmanwin boxcar chebwin flattopwin hann kaiser nuttallwin triang gaussian gausswin tukeywin rectwin welchwin parzenwin System identification arburg aryule invfreq invfreqs invfreqz levinson Sample rate change decimate interp downsample upsample resample upfirdn data2fun Utility buffer findpeaks fracshift marcumq wkeep wrev zerocrossing sampled2continuous schtrig clustersegment signal/NEWS0000644000000000000000000001061012124117010011143 0ustar 00000000000000Summary of important user-visible changes for releases of the signal package =============================================================================== 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/inst/__power.m0000644000000000000000000000507612124117010013243 0ustar 00000000000000## 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; if not, see . ## usage: [P, w] = __power (b, a, [, nfft [, Fs]] [, range] [, units]) ## ## 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. ## TODO: consider folding this into freqz --- just one more parameter to ## TODO: 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/inst/ar_psd.m0000644000000000000000000002646712124117010013070 0ustar 00000000000000%% 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; if not, see . %% Usage: %% [psd,f_out] = ar_psd(a,v,freq,Fs,range,method,plot_type) %% %% Calculate the power spectrum of the autoregressive model %% %% M %% x(n) = sqrt(v).e(n) + SUM a(k).x(n-k) %% k=1 %% where x(n) is the output of the model and e(n) is white noise. %% This function is intended for use with %% [a,v,k] = arburg(x,poles,criterion) %% which use the Burg (1968) method to calculate a "maximum entropy" %% autoregressive model of "x". This function runs on octave and matlab. %% %% If the "freq" argument is a vector (of frequencies) the spectrum is %% calculated using the polynomial method and the "method" argument is %% ignored. For scalar "freq", an integer power of 2, or "method='FFT'", %% causes the spectrum to be calculated by FFT. Otherwise, the spectrum %% is calculated as a polynomial. It may be computationally more %% efficient to use the FFT method if length of the model is not much %% smaller than the number of frequency values. The spectrum is scaled so %% that spectral energy (area under spectrum) is the same as the %% time-domain energy (mean square of the signal). %% %% ARGUMENTS: %% All but the first two arguments are optional and may be empty. %% %% a %% [vector] list of M=(order+1) autoregressive model %% %% coefficients. The first element of "ar_coeffs" is the %% %% zero-lag coefficient, which always has a value of 1. %% %% v %% [real scalar] square of the moving-average coefficient 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 returned values are not required by the caller, the spectrum %% is plotted and nothing is returned. %% psd %% [real vector] estimate of power-spectral density %% f_out %% [real vector] frequency values %% %% N.B. arburg runs in octave and matlab, and does not depend on octave-forge %% or signal-processing-toolbox functions. %% %% 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 %% 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 areguments 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.' ); end 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.' ); end Fs = arg; %% else error( 'ar_psd: control arg must be string.' ); end %% %% 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 ); end end %% 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' ); end 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; end end %% %% 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; end fft_out = polyval( a(len_coeffs:-1:1), exp( (-i*2*pi/Fs) * freq ) ); end %% %% 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); end %% %% 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)]; end %% %% 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)); end end end signal/inst/arburg.m0000644000000000000000000002264112124117010013070 0ustar 00000000000000%% 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; if not, see . %% [a,v,k] = arburg(x,poles,criterion) %% %% Calculate coefficients of an autoregressive (AR) model of complex data %% "x" using the whitening lattice-filter method of Burg (1968). The inverse %% of the model is a moving-average filter which reduces "x" to white noise. %% The power spectrum of the AR model is an estimate of the maximum %% entropy power spectrum of the data. The function "ar_psd" calculates the %% power spectrum of the AR model. %% %% ARGUMENTS: %% x %% [vector] sampled data %% %% poles %% [integer scalar] number of poles in the AR model or %% %% limit to the number of poles if a %% %% valid "stop_crit" is provided. %% %% 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). Recognised values are %% %% 'AKICc' -- approximate corrected Kullback information %% %% criterion (recommended), %% %% 'KIC' -- Kullback information criterion %% %% 'AICc' -- corrected Akaike information criterion %% %% 'AIC' -- Akaike information criterion %% %% 'FPE' -- final prediction error" criterion %% %% The default is to NOT use a model-selection criterion %% %% RETURNED VALUES: %% a %% [polynomial/vector] list of (P+1) autoregression coeffic- %% %% ients; for data input x(n) and white noise e(n), %% %% the model is %% %% P+1 %% %% x(n) = sqrt(v).e(n) + SUM a(k).x(n-k) %% %% k=1 %% %% v %% [real scalar] mean square of residual noise from the %% %% whitening operation of the Burg lattice filter. %% %% k %% [column vector] reflection coefficients defining the %% %% lattice-filter embodiment of the model %% %% HINTS: %% (1) arburg does not remove the mean from the data. You should remove %% the mean from the data if you want a power spectrum. A non-zero mean %% can produce large errors in a power-spectrum estimate. See %% "help detrend". %% (2) If you don't know what the value of "poles" should be, choose the %% largest (reasonable) value you could want and use the recommended %% value, criterion='AKICc', so that arburg can find it. %% E.g. arburg(x,64,'AKICc') %% The AKICc has the least bias and best resolution of the available %% model-selection criteria. %% (3) arburg runs in octave and matlab, does not depend on octave forge %% or signal-processing-toolbox functions. %% (4) 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 biassed 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 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 recognised' ); end else use_inf_crit = 0; use_FPE = 0; end %% %% 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; end %% 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; end %% %% (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; end end %% 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; end 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; end end %% end of for loop %% varargout{1} = [1 a]; varargout{2} = v; if ( nargout>=3 ) varargout{3} = k; end end end %% signal/inst/aryule.m0000644000000000000000000000431412124117010013104 0ustar 00000000000000## 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; if not, see . ## usage: [a, v, k] = aryule (x, p) ## ## fits an AR (p)-model with Yule-Walker estimates. ## x = data vector to estimate ## a: AR coefficients ## v: variance of white noise ## k: reflection coeffients for use in lattice filter ## ## The power spectrum of the resulting filter can be plotted with ## pyulear(x, p), or you can plot it directly with ar_psd(a,v,...). ## ## See also: ## pyulear, power, freqz, impz -- for observing characteristics of the model ## arburg -- for alternative spectral estimators ## ## Example: Use example from arburg, but substitute aryule for arburg. ## ## Note: Orphanidis '85 claims lattice filters are more tolerant of ## truncation errors, which is why you might want to use them. However, ## lacking a lattice filter processor, I haven't tested that the lattice ## filter coefficients are reasonable. 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{w}] =} barthannwin(@var{L}) ## Compute the modified Bartlett-Hann window of lenght L. ## @seealso{rectwin, bartlett} ## @end deftypefn function [w] = barthannwin(L) if (nargin < 1) print_usage; elseif (! isscalar(L) || L < 0) error("L must be a positive integer"); endif L = round(L); if (L == 1) w = 1; else N = L-1; n = 0:N; w = 0.62 -0.48.*abs(n./(L-1) - 0.5)+0.38*cos(2.*pi*(n./(L-1)-0.5)); w = w'; endif endfunction signal/inst/besselap.m0000644000000000000000000000270112124117010013377 0ustar 00000000000000## 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; if not, see . ## Return bessel analog filter prototype. ## ## References: ## ## http://en.wikipedia.org/wiki/Bessel_polynomials function [zero, pole, gain] = besselap (n) if (nargin>1 || nargin<1) print_usage; end ## interpret the input parameters if (!(length(n)==1 && n == round(n) && n > 0)) error ("besselap: filter order n must be a positive integer"); end 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/inst/besself.m0000644000000000000000000000677012124117010013236 0ustar 00000000000000## 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; if not, see . ## 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 ## ## [b,a] = besself(n, [Wl, Wh]) ## band pass filter with edges pi*Wl and pi*Wh radians ## ## [b,a] = besself(n, [Wl, Wh], 'stop') ## band reject filter with edges pi*Wl and pi*Wh 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. function [a, b, c, d] = besself (n, W, varargin) if (nargin>4 || nargin<2) || (nargout>4 || nargout<2) print_usage; end ## interpret the input parameters if (!(length(n)==1 && n == round(n) && n > 0)) error ("besself: filter order n must be a positive integer"); end stop = 0; digital = 0; for i=1:length(varargin) switch varargin{i} case 's', digital = 0; case 'z', digital = 1; case { 'high', 'stop' }, stop = 1; case { 'low', 'pass' }, stop = 0; otherwise, error ("besself: expected [high|stop] or [s|z]"); endswitch endfor [r, c]=size(W); if (!(length(W)<=2 && (r==1 || c==1))) error ("besself: frequency must be given as w0 or [w0, w1]"); elseif (!(length(W)==1 || length(W) == 2)) error ("besself: only one filter band allowed"); elseif (length(W)==2 && !(W(1) < W(2))) error ("besself: first band edge must be smaller than second"); endif if ( digital && !all(W >= 0 & W <= 1)) error ("besself: critical frequencies must be in (0 1)"); elseif ( !digital && !all(W >= 0 )) error ("besself: critical frequencies must be in (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 signal/inst/bilinear.m0000644000000000000000000001043612124117010013372 0ustar 00000000000000## 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; if not, see . ## usage: [Zz, Zp, Zg] = bilinear(Sz, Sp, Sg, T) ## [Zb, Za] = bilinear(Sb, Sa, T) ## ## Transform a s-plane filter specification into a z-plane ## specification. Filters can be specified in either zero-pole-gain or ## transfer function form. The input form does not have to match the ## output form. 1/T is the sampling frequency represented in the z plane. ## ## Note: this differs from the bilinear function in the signal processing ## toolbox, which uses 1/T rather than T. ## ## Theory: Given a piecewise flat filter design, you can transform it ## from the s-plane to the z-plane while maintaining the band edges by ## means of the bilinear transform. This maps the left hand side of the ## s-plane into the interior of the unit circle. The mapping is highly ## non-linear, so you must design your filter with band edges in the ## s-plane positioned at 2/T tan(w*T/2) so that they will be positioned ## at w after the bilinear transform is complete. ## ## The following table summarizes the transformation: ## ## +---------------+-----------------------+----------------------+ ## | Transform | Zero at x | Pole at x | ## | H(S) | H(S) = S-x | H(S)=1/(S-x) | ## +---------------+-----------------------+----------------------+ ## | 2 z-1 | zero: (2+xT)/(2-xT) | zero: -1 | ## | S -> - --- | pole: -1 | pole: (2+xT)/(2-xT) | ## | T z+1 | gain: (2-xT)/T | gain: (2-xT)/T | ## +---------------+-----------------------+----------------------+ ## ## With tedious algebra, you can derive the above formulae yourself by ## substituting the transform for S into H(S)=S-x for a zero at x or ## H(S)=1/(S-x) for a pole at x, and converting the result into the ## form: ## ## H(Z)=g prod(Z-Xi)/prod(Z-Xj) ## ## Please note that a pole and a zero at the same place exactly cancel. ## This is significant since the bilinear transform creates numerous ## extra poles and zeros, most of which cancel. Those which do not ## cancel have a "fill-in" effect, extending the shorter of the sets to ## have the same number of as the longer of the sets of poles and zeros ## (or at least split the difference in the case of the band pass ## filter). There may be other opportunistic cancellations but I will ## not check for them. ## ## Also note that any pole on the unit circle or beyond will result in ## an unstable filter. Because of cancellation, this will only happen ## if the number of poles is smaller than the number of zeros. The ## analytic design methods all yield more poles than zeros, so this will ## not be a problem. ## ## References: ## ## Proakis & Manolakis (1992). Digital Signal Processing. New York: ## Macmillan Publishing Company. 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; end 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"); end ## ---------------- ------------------------- ------------------------ ## 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); end if nargout==2, [Zz, Zp] = zp2tf(Zz, Zp, Zg); endif endfunction signal/inst/bitrevorder.m0000644000000000000000000000552312124117010014135 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{y} @var{i}] =} bitrevorder(@var{x}) ## Reorder x in the bit reversed order ## @seealso{fft,ifft} ## @end deftypefn function [y i] = bitrevorder(x) if(nargin < 1 || nargin >1) print_usage; elseif(log2(length(x)) ~= floor(log2(length(x)))) error('x must have a length equal to a power of 2'); end old_ind = 0:length(x)-1; new_ind = bi2de(fliplr(de2bi(old_ind))); i = new_ind + 1; y(old_ind+1) = x(i); endfunction ## The following functions, de2bi and bi2de, are from the communications package. ## However, the communications package is already dependent on the signal ## package and to avoid circular dependencies their code was copied here. Anyway, ## in the future bitrevorder should be rewritten as to not use this functions ## at all (and pkg can be fixed to support circular dependencies on pkg load ## as it already does for pkg install). ## note that aside copying the code from the communication package, their input ## check was removed since in this context they were always being called with ## nargin == 1 function b = de2bi (d, n, p, f) p = 2; n = floor ( log (max (max (d), 1)) ./ log (p) ) + 1; f = 'right-msb'; d = d(:); if ( any (d < 0) || any (d != floor (d)) ) error ("de2bi: d must only contain non-negative integers"); endif if (isempty (n)) n = floor ( log (max (max (d), 1)) ./ log (p) ) + 1; endif power = ones (length (d), 1) * (p .^ [0 : n-1] ); d = d * ones (1, n); b = floor (rem (d, p*power) ./ power); if (strcmp (f, 'left-msb')) b = b(:,columns(b):-1:1); elseif (!strcmp (f, 'right-msb')) error ("de2bi: unrecognized flag"); endif endfunction function d = bi2de (b, p, f) p = 2; f = 'right-msb'; if ( any (b(:) < 0) || any (b(:) != floor (b(:))) || any (b(:) > p - 1) ) error ("bi2de: d must only contain integers in the range [0, p-1]"); endif if (strcmp (f, 'left-msb')) b = b(:,size(b,2):-1:1); elseif (!strcmp (f, 'right-msb')) error ("bi2de: unrecognized flag"); endif if (length (b) == 0) d = []; else d = b * ( p .^ [ 0 : (columns(b)-1) ]' ); endif endfunction signal/inst/blackmanharris.m0000644000000000000000000000236212124117010014565 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{w}] =} blackmanharris(@var{L}) ## Compute the Blackman-Harris window. ## @seealso{rectwin, bartlett} ## @end deftypefn function [w] = blackmanharris (L) if (nargin < 1) print_usage; elseif(! isscalar(L)) error("L must be a number"); endif if (L == 1) w = 1; else N = L-1; a0 = 0.35875; a1 = 0.48829; a2 = 0.14128; a3 = 0.01168; n = (0 : N)'; w = a0 - a1.*cos(2.*pi.*n./N) + a2.*cos(4.*pi.*n./N) - a3.*cos(6.*pi.*n./N); endif endfunction signal/inst/blackmannuttall.m0000644000000000000000000000240412124117010014755 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{w}] =} blackmannuttall(@var{L}) ## Compute the Blackman-Nuttall window. ## @seealso{nuttallwin, kaiser} ## @end deftypefn function [w] = blackmannuttall(L) if (nargin < 1) print_usage; elseif (! isscalar(L)) error("L must be a number"); endif if (L == 1) w = 1; else N = L-1; a0 = 0.3635819; a1 = 0.4891775; a2 = 0.1365995; a3 = 0.0106411; n = 0:N; w = a0 - a1.*cos(2.*pi.*n./N) + a2.*cos(4.*pi.*n./N) - a3.*cos(6.*pi.*n./N); w = w.'; endif endfunction signal/inst/bohmanwin.m0000644000000000000000000000257312124117010013572 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{w}] =} bohmanwin(@var{L}) ## Compute the Bohman window of lenght L. ## @seealso{rectwin, bartlett} ## @end deftypefn function [w] = bohmanwin(L) if (nargin < 1) print_usage elseif(! isscalar(L)) error("L must be a number"); elseif(L < 0) error('L must be positive'); end if(L ~= floor(L)) L = round(L); warning('L rounded to the nearest integer.'); end if(L == 0) w = []; elseif(L == 1) w = 1; else N = L-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'; end endfunction signal/inst/boxcar.m0000644000000000000000000000176012124117010013063 0ustar 00000000000000## 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; if not, see . ## usage: w = boxcar (n) ## ## Returns the filter coefficients of a rectangular window of length n. function w = boxcar (n) if (nargin != 1) print_usage; elseif !isscalar(n) || n != floor(n) || n <= 0 error ("boxcar: n must be an integer > 0"); endif w = ones(n, 1); endfunction signal/inst/buffer.m0000644000000000000000000001764012124117010013062 0ustar 00000000000000## 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; 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 inetger"); endif if (nargin < 3) p = 0; elseif (!isscalar (p) || p != floor (p) || p >= n) error ("buffer: p must be an inetger 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; while (in > 0) y (1 : in, off) = opt(off:end); off++; in = in - 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]); signal/inst/buttap.m0000644000000000000000000000234612124117010013105 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} buttap (@var{n}) ## Design lowpass analog Butterworth filter. ## ## This function exists only for matlab compatibility 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/inst/butter.m0000644000000000000000000001400712124117010013110 0ustar 00000000000000## Copyright (C) 1999 Paul Kienzle ## Copyright (C) 2003 Doug Stewart ## 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; if not, see . ## Generate a butterworth filter. ## Default is a discrete space (Z) filter. ## ## [b,a] = butter(n, Wc) ## low pass filter with cutoff pi*Wc radians ## ## [b,a] = butter(n, Wc, 'high') ## high pass filter with cutoff pi*Wc radians ## ## [b,a] = butter(n, [Wl, Wh]) ## band pass filter with edges pi*Wl and pi*Wh radians ## ## [b,a] = butter(n, [Wl, Wh], 'stop') ## band reject filter with edges pi*Wl and pi*Wh radians ## ## [z,p,g] = butter(...) ## return filter as zero-pole-gain rather than coefficients of the ## numerator and denominator polynomials. ## ## [...] = butter(...,'s') ## return a Laplace space filter, W can be larger than 1. ## ## [a,b,c,d] = butter(...) ## return state-space matrices ## ## References: ## ## Proakis & Manolakis (1992). Digital Signal Processing. New York: ## Macmillan Publishing Company. function [a, b, c, d] = butter (n, W, varargin) if (nargin>4 || nargin<2) || (nargout>4 || nargout<2) print_usage; end ## interpret the input parameters if (!(length(n)==1 && n == round(n) && n > 0)) error ("butter: filter order n must be a positive integer"); end stop = 0; digital = 1; for i=1:length(varargin) switch varargin{i} case 's', digital = 0; case 'z', digital = 1; case { 'high', 'stop' }, stop = 1; case { 'low', 'pass' }, stop = 0; otherwise, error ("butter: expected [high|stop] or [s|z]"); endswitch endfor [r, c]=size(W); if (!(length(W)<=2 && (r==1 || c==1))) error ("butter: frequency must be given as w0 or [w0, w1]"); elseif (!(length(W)==1 || length(W) == 2)) error ("butter: only one filter band allowed"); elseif (length(W)==2 && !(W(1) < W(2))) error ("butter: first band edge must be smaller than second"); endif if ( digital && !all(W >= 0 & W <= 1)) error ("butter: critical frequencies must be in (0 1)"); elseif ( !digital && !all(W >= 0 )) error ("butter: critical frequencies must be in (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 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; end # pure real value at exp(i*pi) zero = []; gain = C^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 %!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 ) %!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/inst/buttord.m0000644000000000000000000000633212124117010013270 0ustar 00000000000000## 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; if not, see . ## Compute butterworth filter order and cutoff for the desired response ## characteristics. Rp is the allowable decibels of ripple in the pass ## band. Rs is the minimum attenuation in the stop band. ## ## [n, Wc] = buttord(Wp, Ws, Rp, Rs) ## Low pass (WpWs) filter design. Wp is the ## pass band edge and Ws is the stop band edge. Frequencies are ## normalized to [0,1], corresponding to the range [0,Fs/2]. ## ## [n, Wc] = buttord([Wp1, Wp2], [Ws1, Ws2], Rp, Rs) ## Band pass (Ws1Ws) || all(Ws>Wp) || diff(Wp)<=0 || diff(Ws)<=0) error("buttord: Wp(1) Ws); Wp(stop) = 1-Wp(stop); # stop will be at most length 1, so no need to Ws(stop) = 1-Ws(stop); # subtract from ones(1,length(stop)) ## warp the target frequencies according to the bilinear transform Ws = (2/T)*tan(pi*Ws./T); Wp = (2/T)*tan(pi*Wp./T); ## compute minimum n which satisfies all band edge conditions ## the factor 1/length(Wp) is an artificial correction for the ## band pass/stop case, which otherwise significantly overdesigns. qs = log(10^(Rs/10) - 1); qp = log(10^(Rp/10) - 1); n = ceil(max(0.5*(qs - qp)./log(Ws./Wp))/length(Wp)); ## compute -3dB cutoff given Wp, Rp and n Wc = exp(log(Wp) - qp/2/n); ## unwarp the returned frequency Wc = atan(T/2*Wc)*T/pi; ## if high pass, reverse the sense of the test Wc(stop) = 1-Wc(stop); endfunction signal/inst/cceps.m0000644000000000000000000000374312124117010012705 0ustar 00000000000000## Copyright (C) 1994 Dept of Probability Theory and Statistics TU Wien ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See 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 . ## usage: cceps (x [, correct]) ## ## Returns the complex cepstrum of the vector x. ## If the optional argument correct has the value 1, a correction ## method is applied. The default is not to do this. ## Author: Andreas Weingessel ## Apr 1, 1994 ## Last modifified by AW on Nov 8, 1994 function cep = cceps (x, c) if (nargin == 1) c = 0; 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: bad signal x, ", ... "some Fourier coefficients are zero."]; F = fft (x); if (min (abs (F)) == 0) error (bad_signal_message); endif # determine if correction necessary half = fix (nr / 2); cor = 0; 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 signal/inst/cheb.m0000644000000000000000000000305712124117010012507 0ustar 00000000000000## 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; if not, see . ## Usage: cheb (n, x) ## ## Returns the value of the nth-order Chebyshev polynomial calculated at ## the point x. The Chebyshev polynomials are defined by the equations: ## ## / cos(n acos(x), |x| <= 1 ## Tn(x) = | ## \ cosh(n acosh(x), |x| > 1 ## ## If x is a vector, the output is a vector of the same size, where each ## element is calculated as y(i) = Tn(x(i)). 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/inst/cheb1ap.m0000644000000000000000000000257312124117010013113 0ustar 00000000000000## 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; 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 only for matlab compatibility 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/inst/cheb1ord.m0000644000000000000000000001125212124117010013271 0ustar 00000000000000## Copyright (C) 2000 Paul Kienzle ## Copyright (C) 2000 Laurent S. 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; if not, see . ## Compute chebyshev type I filter order and cutoff for the desired response ## characteristics. Rp is the allowable decibels of ripple in the pass ## band. Rs is the minimum attenuation in the stop band. ## ## [n, Wc] = cheb1ord(Wp, Ws, Rp, Rs) ## Low pass (WpWs) filter design. Wp is the ## pass band edge and Ws is the stop band edge. Frequencies are ## normalized to [0,1], corresponding to the range [0,Fs/2]. ## ## [n, Wc] = cheb1ord([Wp1, Wp2], [Ws1, Ws2], Rp, Rs) ## Band pass (Ws1Ws) || all(Ws>Wp) || diff(Wp)<=0 || diff(Ws)<=0) error("cheb1ord: Wp(1) ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} cheb2ap (@var{n}, @var{Rs}) ## Design lowpass analog Chebyshev type II filter. ## ## This function exists only for matlab compatibility 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/inst/cheb2ord.m0000644000000000000000000001122712124117010013274 0ustar 00000000000000## 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; if not, see . ## Compute chebyshev type II filter order and cutoff for the desired response ## characteristics. Rp is the allowable decibels of ripple in the pass ## band. Rs is the minimum attenuation in the stop band. ## ## [n, Wc] = cheb2ord(Wp, Ws, Rp, Rs) ## Low pass (WpWs) filter design. Wp is the ## pass band edge and Ws is the stop band edge. Frequencies are ## normalized to [0,1], corresponding to the range [0,Fs/2]. ## ## [n, Wc] = cheb2ord([Wp1, Wp2], [Ws1, Ws2], Rp, Rs) ## Band pass (Ws1Ws) || all(Ws>Wp) || diff(Wp)<=0 || diff(Ws)<=0) error("cheb2ord: Wp(1) ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See 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 . ## Usage: chebwin (L, at) ## ## Returns the filter coefficients of the L-point Dolph-Chebyshev window ## with at dB of attenuation in the stop-band of the corresponding ## Fourier transform. The default attenuation value is 100 dB. ## ## For the definition of the Chebyshev window, see ## ## * Peter Lynch, "The Dolph-Chebyshev Window: A Simple Optimal Filter", ## Monthly Weather Review, Vol. 125, pp. 655-660, April 1997. ## (http://www.maths.tcd.ie/~plynch/Publications/Dolph.pdf) ## ## * C. Dolph, "A current distribution for broadside arrays which ## optimizes the relationship between beam width and side-lobe level", ## Proc. IEEE, 34, pp. 335-348. ## ## The window is described in frequency domain by the expression: ## ## Cheb(L-1, beta * cos(pi * k/L)) ## W(k) = ------------------------------- ## Cheb(L-1, beta) ## ## with ## ## beta = cosh(1/(L-1) * acosh(10^(at/20)) ## ## and Cheb(m,x) denoting the m-th order Chebyshev polynomial calculated ## at the point x. ## ## Note that the denominator in W(k) above is not computed, and after ## the inverse Fourier transform the window is scaled by making its ## maximum value unitary. ## ## See also: kaiser function w = chebwin (L, at) if (nargin < 1 || nargin > 2) print_usage; elseif (nargin == 1) at = 100; endif if !(isscalar (L) && (L == round(L)) && (L > 0)) error ("chebwin: L has to be a positive integer"); elseif !(isscalar (at) && (at == real (at))) error ("chebwin: at has to be a real scalar"); endif if (L == 1) w = 1; else # beta calculation gamma = 10^(-at/20); beta = cosh(1/(L-1) * acosh(1/gamma)); # freq. scale k = (0:L-1); x = beta*cos(pi*k/L); # Chebyshev window (freq. domain) p = cheb(L-1, x); # inverse Fourier transform if (rem(L,2)) w = real(fft(p)); M = (L+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/L * (0:L-1)); w = real(fft(p)); M = L/2+1; w = w/w(2); w = [w(M:-1:2) w(2:M)]'; endif endif w = w ./ max (w (:)); endfunction signal/inst/cheby1.m0000644000000000000000000000766512124117010012772 0ustar 00000000000000## 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; if not, see . ## Generate an Chebyshev type I filter with Rp dB of pass band 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. function [a,b,c,d] = cheby1(n, Rp, W, varargin) if (nargin>5 || nargin<3) || (nargout>4 || nargout<2) print_usage; endif ## interpret the input parameters if (!(length(n)==1 && n == round(n) && n > 0)) error ("cheby1: filter order n must be a positive integer"); endif stop = 0; digital = 1; for i=1:length(varargin) switch varargin{i} case 's', digital = 0; case 'z', digital = 1; case { 'high', 'stop' }, stop = 1; case { 'low', 'pass' }, stop = 0; otherwise, error ("cheby1: expected [high|stop] or [s|z]"); endswitch endfor [r, c]=size(W); if (!(length(W)<=2 && (r==1 || c==1))) error ("cheby1: frequency must be given as w0 or [w0, w1]"); elseif (!(length(W)==1 || length(W) == 2)) error ("cheby1: only one filter band allowed"); elseif (length(W)==2 && !(W(1) < W(2))) error ("cheby1: first band edge must be smaller than second"); endif if ( digital && !all(W >= 0 & W <= 1)) error ("cheby1: critical frequencies must be in (0 1)"); elseif ( !digital && !all(W >= 0 )) error ("cheby1: critical frequencies must be in (0 inf)"); endif if (Rp < 0) error("cheby1: passband ripple must be positive decibels"); end ## 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 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 signal/inst/cheby2.m0000644000000000000000000001052412124117010012757 0ustar 00000000000000## 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; if not, see . ## Generate an Chebyshev type II filter with Rs dB of stop band 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. function [a,b,c,d] = cheby2(n, Rs, W, varargin) if (nargin>5 || nargin<3) || (nargout>4 || nargout<2) print_usage; end ## interpret the input parameters if (!(length(n)==1 && n == round(n) && n > 0)) error ("cheby2: filter order n must be a positive integer"); end stop = 0; digital = 1; for i=1:length(varargin) switch varargin{i} case 's', digital = 0; case 'z', digital = 1; case { 'high', 'stop' }, stop = 1; case { 'low', 'pass' }, stop = 0; otherwise, error ("cheby2: expected [high|stop] or [s|z]"); endswitch endfor [r, c]=size(W); if (!(length(W)<=2 && (r==1 || c==1))) error ("cheby2: frequency must be given as w0 or [w0, w1]"); elseif (!(length(W)==1 || length(W) == 2)) error ("cheby2: only one filter band allowed"); elseif (length(W)==2 && !(W(1) < W(2))) error ("cheby2: first band edge must be smaller than second"); endif if ( digital && !all(W >= 0 & W <= 1)) error ("cheby2: critical frequencies must be in (0 1)"); elseif ( !digital && !all(W >= 0 )) error ("cheby2: critical frequencies must be in (0 inf)"); endif if (Rs < 0) error("cheby2: stopband attenuation must be positive decibels"); end ## 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 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 signal/inst/chirp.m0000644000000000000000000000632712124117010012716 0ustar 00000000000000## Copyright (C) 1999-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; if not, see . ## usage: y = chirp(t [, f0 [, t1 [, f1 [, form [, phase]]]]]) ## ## Evaluate a chirp signal at time t. A chirp signal is a frequency ## swept cosine wave. ## ## t: vector of times to evaluate the chirp signal ## f0: frequency at time t=0 [ 0 Hz ] ## t1: time t1 [ 1 sec ] ## f1: frequency at time t=t1 [ 100 Hz ] ## form: shape of frequency sweep ## 'linear' f(t) = (f1-f0)*(t/t1) + f0 ## 'quadratic' f(t) = (f1-f0)*(t/t1)^2 + f0 ## 'logarithmic' f(t) = (f1-f0)^(t/t1) + f0 ## phase: phase shift at t=0 ## ## Example ## specgram(chirp([0:0.001:5])); # linear, 0-100Hz in 1 sec ## specgram(chirp([-2:0.001:15], 400, 10, 100, 'quadratic')); ## soundsc(chirp([0:1/8000:5], 200, 2, 500, "logarithmic"),8000); ## ## If you want a different sweep shape f(t), use the following: ## y = cos(2*pi*integral(f(t)) + 2*pi*f0*t + phase); function y = chirp(t, f0, t1, f1, form, phase) if nargin < 1 || nargin > 6 print_usage; endif if nargin < 2, f0 = []; endif if nargin < 3, t1 = []; endif if nargin < 4, f1 = []; endif if nargin < 5, form = []; endif if nargin < 6, phase = []; endif if isempty(f0), f0 = 0; endif if isempty(t1), t1 = 1; endif if isempty(f1), f1 = 100; endif if isempty(form), form = "linear"; endif if isempty(phase), phase = 0; endif phase = 2*pi*phase/360; if strcmp(form, "linear") a = pi*(f1 - f0)/t1; b = 2*pi*f0; y = cos(a*t.^2 + b*t + phase); elseif strcmp(form, "quadratic") a = (2/3*pi*(f1-f0)/t1/t1); b = 2*pi*f0; y = cos(a*t.^3 + b*t + phase); elseif strcmp(form, "logarithmic") a = 2*pi*t1/log(f1-f0); b = 2*pi*f0; x = (f1-f0)^(1/t1); y = cos(a*x.^t + b*t + phase); else error("chirp doesn't understand '%s'",form); endif endfunction %!demo %! specgram(chirp([0:0.001:5]),[],1000); # linear, 0-100Hz in 1 sec %! %------------------------------------------------------------ %! % 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 %! specgram(chirp([-2:0.001:15], 400, 10, 100, 'quadratic')); %! %------------------------------------------------------------ %! % Shows a quadratic chirp of 400 Hz at t=0 and 100 Hz at t=10 %! % Time goes from -2 to 15 seconds. %!demo %! specgram(chirp([0:1/8000:5], 200, 2, 500, "logarithmic"),[],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. signal/inst/clustersegment.m0000644000000000000000000000456212124117010014654 0ustar 00000000000000## 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; 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 result is returned in a cell of size ## 1-by-Np, being Np the numer of rows in @var{unos}. Each element of the cell ## has two rows. The first row is the inital index of a sequence of 1's and the ## second row is the end index of that sequence. ## ## If Np == 1 the output is a matrix with two rows. ## ## @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; end if xhi(i,end)==1 % last event was up contRange{i}(end+1) = Na; end tLen = length(contRange{i}); if tLen ~=0 contRange{i}=reshape(contRange{i},2,tLen/2); end end if Np == 1 contRange = cell2mat (contRange); end 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/inst/cmorwavf.m0000644000000000000000000000217112124117010013426 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{psi,x}] =} cmorwavf (@var{lb,ub,n,fb,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/inst/cohere.m0000644000000000000000000000366112124117010013054 0ustar 00000000000000%% 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; 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.' ); end 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} = []; end end 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; end pwelch(saved_compatib); saved_compatib = 0; end signal/inst/convmtx.m0000644000000000000000000000343512124117010013304 0ustar 00000000000000## 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; 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/inst/cplxreal.m0000644000000000000000000000446412124117010013423 0ustar 00000000000000%% 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; if not, see . %% -*- texinfo -*- %% @deftypefn {Function File} {[@var{zc}, @var{zr}] =} cplxreal (@var{z}, @var{thresh}) %% Split the vector z into its complex (@var{zc}) and real (@var{zr}) elements, %% eliminating one of each complex-conjugate pair. %% %% INPUTS:@* %% @itemize %% @item %% @var{z} = row- or column-vector of complex numbers@* %% @item %% @var{thresh} = tolerance threshold for numerical comparisons (default = 100*eps) %% @end itemize %% %% RETURNED:@* %% @itemize %% @item %% @var{zc} = elements of @var{z} having positive imaginary parts@* %% @item %% @var{zr} = elements of @var{z} having zero imaginary part@* %% @end itemize %% %% Each complex element of @var{z} is assumed to have a complex-conjugate %% counterpart elsewhere in @var{z} as well. Elements are declared real %% if their imaginary parts have magnitude less than @var{thresh}. %% %% @seealso{cplxpair} %% @end deftypefn function [zc,zr] = cplxreal (z, thresh = 100*eps) % interesting for testing: if nargin<2, thresh=1E-3; end if isempty(z) zc=[]; zr=[]; else zcp = cplxpair(z); % sort complex pairs, real roots at end nz = length(z); nzrsec = 0; i=nz; while i && abs(imag(zcp(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; if not, see . %% Usage: %% [Pxx,freq] = cpsd(x,y,window,overlap,Nfft,Fs,range) %% %% Estimate cross power spectrum of data "x" and "y" by the Welch (1967) %% periodogram/FFT method. %% See "help pwelch" for description of arguments, hints and references function [varargout] = cpsd(varargin) %% Check fixed argument if (nargin < 2 || nargin > 7) print_usage (); end 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} = []; end end 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; end end signal/inst/csd.m0000644000000000000000000000362312124117010012356 0ustar 00000000000000%% 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; 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.' ); end 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} = []; end end 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; end pwelch(saved_compatib); end signal/inst/czt.m0000644000000000000000000000610112124117010012377 0ustar 00000000000000## 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; if not, see . ## usage y=czt(x, m, w, a) ## ## Chirp z-transform. Compute the frequency response starting at a and ## stepping by w for m steps. a is a point in the complex plane, and ## w is the ratio between points in each step (i.e., radius increases ## exponentially, and angle increases linearly). ## ## To evaluate the frequency response for the range f1 to f2 in a signal ## with sampling frequency Fs, use the following: ## m = 32; ## number of points desired ## w = exp(-j*2*pi*(f2-f1)/((m-1)*Fs)); ## freq. step of f2-f1/m ## a = exp(j*2*pi*f1/Fs); ## starting at frequency f1 ## y = czt(x, m, w, a); ## ## If you don't specify them, then the parameters default to a fourier ## transform: ## m=length(x), w=exp(-j*2*pi/m), a=1 ## ## If x is a matrix, the transform will be performed column-by-column. ## 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/inst/data2fun.m0000644000000000000000000001120012124117010013277 0ustar 00000000000000%% 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; if not, see . %% -*- texinfo -*- %% @deftypefn {Function File} {[@var{fhandle}, @var{fullname}] = } data2fun (@var{ti}, @var{yi}) %% @deftypefnx {Function File} {[ @dots{} ] = } data2fun (@var{ti}, @var{yi},@var{property},@var{value}) %% Creates 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 property-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{tmpnam} and the file is created in the current directory. @var{value} %% must not have an extension, since .m will be appended. %% Numerical value 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) %% 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); end if given.file %% TODO: check that file will be in the path. Otherwise fhabdle(0) fails. if !isempty(varargin{idx(1)+1}) [DIR fname] = fileparts(varargin{idx(1)+1}); else [DIR fname] = fileparts (tmpnam (pwd (),"agen_")); end interp_args(idx(1)+[0 1]) = []; end if isempty(interp_args) interp_args = {"spline"}; end end 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"... " end\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); disp(["Function generated: " fullfname ]); fhandle = eval(["@" fname]); else fullfname = ""; fhandle = @(t_) ppval (pp, t_); end 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"]; end 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 %! [fhandle fname] = data2fun(t,y,"file","testdata2fun"); %! yt = testdata2fun(t); %! %! assert(y,yt); %! assert(y,fhandle(t)); %! %! delete(fname); %! delete([fname(1:end-2) ".mat"]); %!test %! [fhandle fname] = data2fun(t,y,"file",""); %! yt = testdata2fun(t); %! %! assert(y,yt); %! assert(y,fhandle(t)); %! %! delete(fname); %! delete([fname(1:end-2) ".mat"]); %!test %! [fhandle fname] = data2fun(t,y,"file","testdata2fun","interp","linear"); %! yt = testdata2fun(t); %! %! assert(y,yt); %! assert(y,fhandle(t)); %! %! delete(fname); %! delete([fname(1:end-2) ".mat"]); signal/inst/dct.m0000644000000000000000000000527612124117010012365 0ustar 00000000000000## 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; if not, see . ## y = dct (x, n) ## Computes the discrete cosine transform of x. If n is given, then ## x is padded or trimmed to length n before computing the transform. ## If x is a matrix, compute the transform along the columns of the ## the matrix. The transform is faster if x is real-valued and even ## length. ## ## The discrete cosine transform X of x can be defined as follows: ## ## N-1 ## X[k] = w(k) sum x[n] cos (pi (2n+1) k / 2N ), k = 0, ..., N-1 ## n=0 ## ## with w(0) = sqrt(1/N) and w(k) = sqrt(2/N), k = 1, ..., N-1. There ## are other definitions with different scaling of X[k], but this form ## is common in image processing. ## ## See also: idct, dct2, idct2, dctmtx ## 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/inst/dct2.m0000644000000000000000000000233112124117010012434 0ustar 00000000000000## 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; if not, see . ## y = dct2 (x) ## Computes the 2-D discrete cosine transform of matrix x ## ## y = dct2 (x, m, n) or y = dct2 (x, [m n]) ## Computes the 2-D DCT of x after padding or trimming rows to m and ## columns to n. 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/inst/dctmtx.m0000644000000000000000000000307512124117010013111 0ustar 00000000000000## 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; if not, see . ## T = dctmtx (n) ## Return the DCT transformation matrix of size n x n. ## ## If A is an n x n matrix, then the following are true: ## T*A == dct(A), T'*A == idct(A) ## T*A*T' == dct2(A), T'*A*T == idct2(A) ## ## A dct transformation matrix is useful for doing things like jpeg ## image compression, in which an 8x8 dct matrix is applied to ## non-overlapping blocks throughout an image and only a subblock on the ## top left of each block is kept. During restoration, the remainder of ## the block is filled with zeros and the inverse transform is applied ## to the block. ## ## See also: dct, idct, dct2, idct2 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/inst/decimate.m0000644000000000000000000000604612124117010013362 0ustar 00000000000000## 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; if not, see . ## usage: y = decimate(x, q [, n] [, ftype]) ## ## Downsample the signal x by a factor of q, using an order n filter ## of ftype 'fir' or 'iir'. By default, an order 8 Chebyshev type I ## filter is used or a 30 point FIR filter if ftype is 'fir'. Note ## that q must be an integer for this rate change method. ## ## Example ## ## Generate a signal that starts away from zero, is slowly varying ## ## at the start and quickly varying at the end, decimate and plot. ## ## Since it starts away from zero, you will see the boundary ## ## effects of the antialiasing filter clearly. Next you will see ## ## how it follows the curve nicely in the slowly varying early ## ## part of the signal, but averages the curve in the quickly ## ## varying late part of the signal. ## t=0:0.01:2; x=chirp(t,2,.5,10,'quadratic')+sin(2*pi*t*0.4); ## y = decimate(x,4); # 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 function y = decimate(x, q, n, ftype) if nargin < 1 || nargin > 4 print_usage; elseif q != fix(q) error("decimate only works with integer q."); endif if nargin<3 ftype='iir'; n=[]; elseif nargin==3 if ischar(n) ftype=n; n=[]; else ftype='iir'; endif endif fir = strcmp(ftype, 'fir'); if isempty(n) if fir, n=30; else n=8; endif 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. signal/inst/dftmtx.m0000644000000000000000000000246512124117010013116 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{d} = } dftmtx (@var{n}) ## ## If @var{n} is a scalar, produces a @var{n}-by-@var{n} matrix @var{d} ## such that the Fourier transform of a column vector of length @var{n} ## is given by @code{dftmtx(@var{n}) * x} and the inverse Fourier transform ## is given by @code{inv(dftmtx(@var{n})) * x}. In general this is less ## efficient than calling the @dfn{fft} and @dfn{ifft} directly. ## @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/inst/diric.m0000644000000000000000000000222112124117010012670 0ustar 00000000000000## 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; 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/inst/downsample.m0000644000000000000000000000247012124117010013755 0ustar 00000000000000## 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 nth 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 nth 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; end if phase > n - 1 warning("This is incompatible with Matlab (phase = 0:n-1). See ... octave-forge signal package release notes for details.") end if isvector(x) y = x(phase + 1:n:end); else y = x(phase + 1:n:end,:); end 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/inst/dst.m0000644000000000000000000000265512124117010012403 0ustar 00000000000000## 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)); end # 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/inst/dwt.m0000644000000000000000000000226412124117010012403 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{ca} @var{cd}] =} dwt(@var{x,lo_d,hi_d}) ## Comupte de discrete wavelet transform of x with one level. ## @end deftypefn function [ca cd] = dwt(x,lo_d,hi_d) if (nargin < 3|| nargin > 3) print_usage; elseif(~isvector(x) || ~isvector(lo_d) || ~isvector(hi_d)) error('x, hi_d and lo_d must be vectors'); end h = filter(hi_d,1,x); g = filter(lo_d,1,x); cd = downsample(h,2); ca = downsample(g,2); endfunction signal/inst/ellip.m0000644000000000000000000001124012124117010012704 0ustar 00000000000000## 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; if not, see . ## N-ellip 0.2.1 ##usage: [Zz, Zp, Zg] = ellip(n, Rp, Rs, Wp, stype,'s') ## ## Generate an Elliptic or Cauer filter (discrete and contnuious). ## ## [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. ## - Kienzle, Paul, functions from Octave-Forge, 1999 (http://octave.sf.net). function [a,b,c,d] = ellip(n, Rp, Rs, W, varargin) if (nargin>6 || nargin<4) || (nargout>4 || nargout<2) print_usage; endif ## interpret the input parameters if (!(length(n)==1 && n == round(n) && n > 0)) error ("ellip: filter order n must be a positive integer"); endif stop = 0; digital = 1; for i=1:length(varargin) switch varargin{i} case 's', digital = 0; case 'z', digital = 1; case { 'high', 'stop' }, stop = 1; case { 'low', 'pass' }, stop = 0; otherwise, error ("ellip: expected [high|stop] or [s|z]"); endswitch endfor [r, c]=size(W); if (!(length(W)<=2 && (r==1 || c==1))) error ("ellip: frequency must be given as w0 or [w0, w1]"); elseif (!(length(W)==1 || length(W) == 2)) error ("ellip: only one filter band allowed"); elseif (length(W)==2 && !(W(1) < W(2))) error ("ellip: first band edge must be smaller than second"); endif if ( digital && !all(W >= 0 & W <= 1)) error ("ellip: critical frequencies must be in (0 1)"); elseif ( !digital && !all(W >= 0 )) error ("ellip: critical frequencies must be in (0 inf)"); endif if (Rp < 0) error("ellip: passband ripple must be positive decibels"); endif if (Rs < 0) error("ellip: stopband ripple must be positive decibels"); end ##Prewarp the digital frequencies if digital T = 2; # sampling frequency of 2 Hz W = 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 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 %! clc %! disp('---------------------------> NELLIP 0.2 EXAMPLE <-------------------------') %! x=input("Let's calculate the filter order: [ENTER]"); %! disp("") %! x=input("[n, Ws] = ellipord([.1 .2],.4,1,90); [ENTER]"); %! [n, Ws] = ellipord([.1 .2],.4,1,90) %! disp("") %! x=input("Let's calculate the filter: [ENTER]"); %! disp("") %! x=input("[b,a]=ellip(5,1,90,[.1,.2]); [ENTER]"); %! [b,a]=ellip(5,1,90,[.1,.2]) %! disp("") %! x=input("Let's calculate the frequency response: [ENTER]"); %! disp("") %! x=input("[h,w]=freqz(b,a); [ENTER]"); %! [h,w]=freqz(b,a); %! %! xlabel("Frequency"); %! ylabel("abs(H[w])[dB]"); %! axis([0,1,-100,0]); %! plot(w./pi, 20*log10(abs(h)), ';;') %! %! hold('on'); %! x=ones(1,length(h)); %! plot(w./pi, x.*-1, ';-1 dB;') %! plot(w./pi, x.*-90, ';-90 dB;') %! hold('off'); %! %! xlabel("") %! ylabel("") %! clc signal/inst/ellipap.m0000644000000000000000000000307612124117010013235 0ustar 00000000000000## 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; 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 only for matlab compatibility 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/inst/ellipord.m0000644000000000000000000000605012124117010013414 0ustar 00000000000000## 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; if not, see . ## usage: [n,wp] = ellipord(wp,ws, rp,rs) ## ## Calculate the order for the elliptic filter (discrete) ## wp: Cutoff frequency ## ws: Stopband edge ## rp: decibels of ripple in the passband. ## rs: decibels of ripple in the stopband. ## ## References: ## ## - Lamar, Marcus Vinicius, Notas de aula da disciplina TE 456 - Circuitos ## Analogicos II, UFPR, 2001/2002. function [n, Wp] = ellipord(Wp, Ws, Rp, Rs) [rp, cp]=size(Wp); [rs, cs]=size(Ws); if ( !(length(Wp)<=2 && (rp==1 || cp==1) && length(Ws)<=2 && (rs==1 || cs==1)) ) error ("ellipord: frequency must be given as w0 or [w0, w1]"); elseif (!all(Wp >= 0 & Wp <= 1 & Ws >= 0 & Ws <= 1)) ##### error ("ellipord: critical frequencies must be in (0 1)"); elseif (!(length(Wp)==1 || length(Wp) == 2 & length(Ws)==1 || length(Ws) == 2)) error ("ellipord: only one filter band allowed"); elseif (length(Wp)==2 && !(Wp(1) < Wp(2))) error ("ellipord: first band edge must be smaller than second"); elseif (length(Ws)==2 && !(length(Wp)==2)) error ("ellipord: you must specify band pass borders."); elseif (length(Wp)==2 && length(Ws)==2 && !(Ws(1) < Wp(1) && Ws(2) > Wp(2)) ) error ("ellipord: ( Wp(1), Wp(2) ) must be inside of interval ( Ws(1), Ws(2) )"); elseif (length(Wp)==2 && length(Ws)==1 && !(Ws < Wp(1) || Ws > Wp(2)) ) error ("ellipord: Ws must be out of interval ( Wp(1), Wp(2) )"); endif # sampling frequency of 2 Hz T = 2; Wpw = tan(pi.*Wp./T); # prewarp Wsw = tan(pi.*Ws./T); # prewarp ##pass/stop band to low pass filter transform: if (length(Wpw)==2 && length(Wsw)==2) wp=1; w02 = Wpw(1) * Wpw(2); # Central frequency of stop/pass band (square) w3 = w02/Wsw(2); w4 = w02/Wsw(1); if (w3 > Wsw(1)) ws = (Wsw(2)-w3)/(Wpw(2)-Wpw(1)); elseif (w4 < Wsw(2)) ws = (w4-Wsw(1))/(Wpw(2)-Wpw(1)); else ws = (Wsw(2)-Wsw(1))/(Wpw(2)-Wpw(1)); endif elseif (length(Wpw)==2 && length(Wsw)==1) wp=1; w02 = Wpw(1) * Wpw(2); if (Wsw > Wpw(2)) w3 = w02/Wsw; ws = (Wsw - w3)/(Wpw(2) - Wpw(1)); else w4 = w02/Wsw; ws = (w4 - Wsw)/(Wpw(2) - Wpw(1)); endif 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)); endfunction signal/inst/fht.m0000644000000000000000000000404412124117010012364 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {m = } fht ( d, n, dim ) ## @cindex linear algebra ## The function fht calculates Fast Hartley Transform ## where @var{d} is the real input vector (matrix), and @var{m} ## is the real-transform vector. For matrices 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(); end if ( nargin == 3 ) Y = fft(d,n,dim); elseif ( nargin == 2 ) Y = fft(d,n); else Y = fft(d); end 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; # end end %! %!assert( fht([1 2 3 4]),[10 -4 -2 0] ) %! signal/inst/filtfilt.m0000644000000000000000000000764712124117010013434 0ustar 00000000000000## 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; if not, see . ## usage: y = filtfilt(b, a, x) ## ## Forward and reverse filter the signal. This corrects for phase ## distortion introduced by a one-pass filter, though it does square the ## magnitude response in the process. That's the theory at least. In ## practice the phase correction is not perfect, and magnitude response ## is distorted, particularly in the stop band. #### ## Example ## [b, a]=butter(3, 0.1); % 10 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;') ## TODO: (pkienzle) 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; end 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; end if lb < n, b(n) = 0; end ## 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 end 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); %!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/inst/filtic.m0000644000000000000000000000673712124117010013070 0ustar 00000000000000## 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; if not, see . ## 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 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); signal/inst/findpeaks.m0000644000000000000000000002161012124117010013545 0ustar 00000000000000## 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; 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 intercal here 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 crosses the @asis{"baseline"} value. The ## width of the peak is calculated by @command{diff(roots)}. ## @end table ## ## This function accepts property-value pair given in the list below: ## ## @table @asis ## @item "MinPeakHeight" ## Minimum peak height (positive scalar). Only peaks that exceed this ## value will be returned. For data taking positive and negative values ## use the option "DoubleSided". Default value @code{2*std (abs (detrend ## (data,0)))}. ## ## @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. ## Default value 4. ## ## @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 neighborhood size is equal to the value of ## @asis{"MinPeakDistance"}. The width is evaluated at the half height ## of the peak with baseline at "MinPeakHeight". Default value 2. ## ## @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) # --- Parse arguments --- # __data__ = abs (detrend (data,0)); posscal = @(x)isscalar (x) && x >= 0; parser = inputParser (); parser.FunctionName = "findpeaks"; parser = addParamValue (parser,"MinPeakHeight", 2*std (__data__),posscal); parser = addParamValue (parser,"MinPeakDistance",4,posscal); parser = addParamValue (parser,"MinPeakWidth",2,posscal); parser = addSwitch (parser,"DoubleSided"); parser = parse(parser,varargin{:}); minH = parser.Results.MinPeakHeight; minD = parser.Results.MinPeakDistance; minW = parser.Results.MinPeakWidth; dSided = parser.Results.DoubleSided; clear parser posscal # ------ # if dSided [data __data__] = deal (__data__, data); elseif min(data)<0 error ("findpeaks:InvalidArgument", 'Data contains negative values. You may want to "DoubleSided" option'); end % Rough stimates 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. idx = find (df1.*circshift(df1,1)<0 & df2<0)-1; % 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 (idx_s - idx_s'); 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 end endwhile idx = idx_pruned; end % 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% if minW > 0 %% 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 = length(idx); np = length(data); struct_count = 0; for i=1:n ind = (round (max(idx(i)-minD/2,1)) : ... round (min(idx(i)+minD/2,np)))'; pp = polyfit (ind,data(ind),2); H = pp(3) - pp(2)^2/(4*pp(1)); %% 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"); rz = roots ([pp(1:2) pp(3)-mean([H,minH])]); width = abs (diff (rz)); if width < minW || pp(1) > 0 || H < minH || data(idx(i)) < 0.99*H idx_pruned = setdiff (idx_pruned, idx(i)); elseif nargout >= 1 struct_count++; extra.parabol(struct_count).x = ind([1 end]); extra.parabol(struct_count).pp = pp; extra.roots(struct_count,1:2) = rz; extra.height(struct_count) = H; extra.baseline(struct_count) = mean([H,minH]); end %% debug # set(h(2),"xdata",idx_pruned,"ydata",data(idx_pruned)) # pause(0.2) end end idx = idx_pruned; if dSided pks = __data__(idx); else pks = data(idx); end if nargout >=1 varargout{1} = extra; end 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),'.m') %! subplot(1,2,2) %! plot(t,data2,t(idx2),data2(idx2),".m;>2*std;",t(idx3),data2(idx3),"or;>0.1;") %! 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),'.r') %! subplot(1,2,2) %! plot(t,data,t(idx2),data(idx2),'.r') %! %! #---------------------------------------------------------------------------- %! # Noisy data may need tunning of the parameters. In the 2nd example, %! # MinPeakDistance is used as a smoother of the peaks. signal/inst/fir1.m0000644000000000000000000001277212124117010012453 0ustar 00000000000000## 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; if not, see . ## usage: b = fir1(n, w [, type] [, window] [, noscale]) ## ## Produce an order n FIR filter with the given frequency cutoff, ## returning the n+1 filter coefficients in b. ## ## n: order of the filter (1 less than the length of the filter) ## w: band edges ## strictly increasing vector in range [0, 1] ## singleton for highpass or lowpass, vector pair for bandpass or ## bandstop, or vector for alternating pass/stop filter. ## type: choose between pass and stop bands ## 'high' for highpass filter, cutoff at w ## 'stop' for bandstop filter, edges at w = [lo, hi] ## 'DC-0' for bandstop as first band of multiband filter ## 'DC-1' for bandpass as first band of multiband filter ## window: smoothing window ## defaults to hamming(n+1) row vector ## returned filter is the same shape as the smoothing window ## noscale: choose whether to normalize or not ## 'scale': set the magnitude of the center of the first passband to 1 ## 'noscale': don't normalize ## ## To apply the filter, use the return vector b: ## y=filter(b,1,x); ## ## Examples: ## freqz(fir1(40,0.3)); ## freqz(fir1(15,[0.2, 0.5], 'stop')); # note the zero-crossing at 0.1 ## freqz(fir1(15,[0.2, 0.5], 'stop', 'noscale')); ## TODO: Consider using exact expression (in terms of sinc) for the ## TODO: impulse response rather than relying on fir2. ## TODO: Find reference to the requirement that order be even for ## TODO: filters that end high. Figure out what to do with the ## TODO: 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);end if isempty(arg) continue; end # 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; end 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, 512, 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')); signal/inst/fir2.m0000644000000000000000000001556712124117010012461 0ustar 00000000000000## 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; if not, see . ## usage: b = fir2(n, f, m [, grid_n [, ramp_n]] [, window]) ## ## Produce an FIR filter of order n with arbitrary frequency response, ## returning the n+1 filter coefficients in b. ## ## n: order of the filter (1 less than the length of the filter) ## f: frequency at band edges ## f is a vector of nondecreasing elements in [0,1] ## the first element must be 0 and the last element must be 1 ## if elements are identical, it indicates a jump in freq. response ## m: magnitude at band edges ## m is a vector of length(f) ## grid_n: length of ideal frequency response function ## defaults to 512, should be a power of 2 bigger than n/2 ## ramp_n: transition width for jumps in filter response ## defaults to grid_n/25; a wider ramp gives wider transitions ## but has better stopband characteristics. ## window: smoothing window ## defaults to hamming(n+1) row vector ## returned filter is the same shape as the smoothing window ## ## To apply the filter, use the return vector b: ## y=filter(b,1,x); ## Note that plot(f,m) shows target response. ## ## 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;'); 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 %!test %! 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)) %!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]; %! %! title('Theoretical/Synthesized CLASS spectrum'); %! xlabel('Normalized frequency (Fs=2)'); %! ylabel('Magnitude'); %! %! 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; %! xlabel(''); ylabel(''); title(''); signal/inst/firls.m0000644000000000000000000001007112124117010012717 0ustar 00000000000000## 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; if not, see . ## b = firls(N, F, A); ## b = firls(N, F, A, W); ## ## FIR filter design using least squares method. Returns a length N+1 ## linear phase filter such that the integral of the weighted mean ## squared error in the specified bands is minimized. ## ## 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. ## ## A specifies the amplitude of the desired response at each band edge. ## ## W is an optional weighting function that contains one value for each ## band that weights the mean squared error in that band. A must be the ## same length as F, and W must be half the length of F. N must be ## even. If given an odd value, firls increments it by 1. ## ## The least squares optimization algorithm for computing FIR filter ## coefficients is derived in detail in: ## ## I. Selesnick, "Linear-Phase FIR Filter Design by Least Squares," ## http://cnx.org/content/m10577 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/inst/flattopwin.m0000644000000000000000000000247112124117010013774 0ustar 00000000000000## Author: Paul Kienzle (2004) ## This program is granted to the public domain. ## flattopwin(L, [periodic|symmetric]) ## ## Return the window f(w): ## ## f(w) = 1 - 1.93 cos(2 pi w) + 1.29 cos(4 pi w) ## - 0.388 cos(6 pi w) + 0.0322cos(8 pi w) ## ## where w = i/(L-1) for i=0:L-1 for a symmetric window, or ## w = i/L for i=0:L-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. function w = flattopwin (L, sym) if nargin == 0 || nargin > 2 print_usage; endif divisor = L-1; if nargin > 1 match = strmatch(sym,['periodic';'symmetric']); if isempty(match), error("window type must be periodic or symmetric"); elseif match == 1 divisor = L; else divisor = L-1; endif endif if (L == 1) w = 1; else x = 2*pi*[0:L-1]'/divisor; 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 signal/inst/fracshift.m0000644000000000000000000001072712124117010013561 0ustar 00000000000000## 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; if not, see . ## -*- 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. ## @end deftypefn ## @seealso{circshift} ## 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 nargchk(2,3,nargin) print_usage; endif; ## if the delay is an exact integer, use circshift if d==fix(d) y=circshift(x,d); return endif; ## filter design if required if (nargin < 4) ## properties of the interpolation filter log10_rejection = -3.0; stopband_cutoff_f = 1.0 / 2.0; roll_off_width = stopband_cutoff_f / 10; ## determine filter length ## use empirical formula from [1] 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*stopband_cutoff_f*sinc(2*stopband_cutoff_f*(t-(d-fix(d)))); ## determine parameter of Kaiser window ## use empirical formula from [1] 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 (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; 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("fracshift.m: the filter h should be a vector"); 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); y = xfilt(offset+1:offset+Ly,:); y=circshift(y,fix(d)); if isrowvector, y=y.'; endif endfunction %!test %! N=1024; %! d=1.5; %! t=(0:N-1)-N/2; %! tt=t-d; %! err=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); %! [y,h]=fracshift(x,d); %! xx=exp(-tt'.^2/(2*sigma)).*sin(2*pi*f0*tt' + phi0); %! err(n+1)=max(abs(y-xx)); %! endfor; %! rolloff=.1; %! rejection=10^-3; %! idx_inband=1:ceil((1-rolloff)*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; if not, see . ## Usage: H = freqs(B,A,W); ## ## Compute the s-plane frequency response of the IIR filter B(s)/A(s) as ## H = polyval(B,j*W)./polyval(A,j*W). If called with no output ## argument, a plot of magnitude and phase are displayed. ## ## Example: ## B = [1 2]; A = [1 1]; ## w = linspace(0,4,128); ## freqs(B,A,w); function [H] = freqs(B,A,W) if (nargin ~= 3 || nargout>1) print_usage; end H = polyval(B,j*W)./polyval(A,j*W); if nargout<1 freqs_plot(W,H); end endfunction %!demo %! B = [1 2]; %! A = [1 1]; %! w = linspace(0,4,128); %! freqs(B,A,w); signal/inst/freqs_plot.m0000644000000000000000000000301012124117010013751 0ustar 00000000000000## 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; 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/inst/fwhm.m0000644000000000000000000001343412124117010012547 0ustar 00000000000000%% Author: Petr Mikulik (2009) %% This program is granted to the public domain. %% Compute peak full-width at half maximum (FWHM) or at another level of peak %% maximum for vector or matrix data y, optionally sampled as y(x). If y is %% a matrix, return FWHM for each column as a row vector. %% Syntax: %% f = fwhm({x, } y {, 'zero'|'min' {, 'rlevel', rlevel}}) %% f = fwhm({x, } y {, 'alevel', alevel}) %% Examples: %% f = fwhm(y) %% f = fwhm(x, y) %% f = fwhm(x, y, 'zero') %% f = fwhm(x, y, 'min') %% f = fwhm(x, y, 'alevel', 15.3) %% f = fwhm(x, y, 'zero', 'rlevel', 0.5) %% f = fwhm(x, y, 'min', 'rlevel', 0.1) %% %% The default option 'zero' computes fwhm at half maximum, i.e. 0.5*max(y). %% The option 'min' computes fwhm at the middle curve, i.e. 0.5*(min(y)+max(y)). %% %% The option 'rlevel' computes full-width at the given relative level of peak %% profile, i.e. at rlevel*max(y) or rlevel*(min(y)+max(y)), respectively. %% For example, fwhm(..., 'rlevel', 0.1) computes full width at 10 % of peak %% maximum with respect to zero or minimum; FWHM is equivalent to %% fwhm(..., 'rlevel', 0.5). %% %% The option 'alevel' computes full-width at the given absolute level of y. %% %% Return 0 if FWHM does not exist (e.g. monotonous function or the function %% does not cut horizontal line at rlevel*max(y) or rlevel*(max(y)+min(y)) or %% alevel, respectively). %% %% Compatibility: Octave 3.x, Matlab function myfwhm = fwhm (y, varargin) if nargin < 1 || nargin > 5 print_usage; end 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; end 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'); end level = varargin{k}; if ~isreal(level) || length(level) > 1 error('argument of "alevel" must be real number'); end k = k+1; break end if any(strcmp(varargin{k}, {'zero', 'min'})) opt = varargin{k}; k = k+1; end if k > length(varargin) break; end if strcmp(varargin{k}, 'rlevel') k = k+1; if k > length(varargin) error('option "rlevel" requires an argument'); end 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)'); end k = k+1; break end break end if k ~= length(varargin)+1 error('fwhm: extraneous option(s)'); end end % test the y matrix [nr, nc] = size(y); if (nr == 1 && nc > 1) y = y'; nr = nc; nc = 1; end if length(x) ~= nr error('dimension of input arguments do not match'); end % 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); end end % 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); end [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; end end end %!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/inst/fwht.m0000644000000000000000000000500712124117010012553 0ustar 00000000000000## Copyright (C) 2013 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; 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 ## Author: Mike Miller 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 input validation %!error fwht (); %!error fwht (1, 2, 3, 4); %!error fwht (0, 0); %!error fwht (0, 5); %!error fwht (0, [], "invalid"); signal/inst/gauspuls.m0000644000000000000000000000226212124117010013446 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{y}] =} gauspuls(@var{t},@var{fc},@var{bw}) ## Return the Gaussian modulated sinusoidal pulse. ## @end deftypefn function [y] = gauspuls(t, fc = 1e3, bw = 0.5) if nargin<1, print_usage; end if fc < 0 , error("fc must be positive"); end if bw <= 0, error("bw must be stricltly positive"); end 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 signal/inst/gaussian.m0000644000000000000000000000250112124117010013411 0ustar 00000000000000## 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; if not, see . ## usage: w = gaussian(n, a) ## ## Generate an n-point gaussian convolution window of the given ## width. Use larger a for a narrower window. Use larger n for ## longer tails. ## ## w = exp ( -(a*x)^2/2 ) ## ## for x = linspace ( -(n-1)/2, (n-1)/2, n ). ## ## 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). function x = gaussian(n, w) if nargin < 1 || nargin > 2 print_usage; end if nargin == 1, w = 1; endif x = exp(-0.5*(([0:n-1]'-(n-1)/2)*w).^2); endfunction signal/inst/gausswin.m0000644000000000000000000000216212124117010013442 0ustar 00000000000000## 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; if not, see . ## usage: w = gausswin(L, a) ## ## Generate an L-point gaussian window of the given width. Use larger a ## for a narrow window. Use larger L for a smoother curve. ## ## w = exp ( -(a*x)^2/2 ) ## ## for x = linspace(-(L-1)/L, (L-1)/L, L) function x = gausswin(L, w) if nargin < 1 || nargin > 2 print_usage; end if nargin == 1, w = 2.5; endif x = exp ( -0.5 * ( w/L * [ -(L-1) : 2 : L-1 ]' ) .^ 2 ); endfunction signal/inst/gmonopuls.m0000644000000000000000000000205612124117010013627 0ustar 00000000000000## 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; 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; end if fc < 0 , error("fc must be positive"); end y = 2*sqrt(exp(1)) .* pi.*t.*fc.*exp(-2 .* (pi.*t.*fc).^2); endfunction signal/inst/grpdelay.m0000644000000000000000000002362712124117010013422 0ustar 00000000000000## 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; if not, see . ## Compute the group delay of a filter. ## ## [g, w] = grpdelay(b) ## returns the group delay g of the FIR filter with coefficients b. ## The response is evaluated at 512 angular frequencies between 0 and ## pi. w is a vector containing the 512 frequencies. ## The group delay is in units of samples. It can be converted ## to seconds by multiplying by the sampling period (or dividing by ## the sampling rate fs). ## ## [g, w] = grpdelay(b,a) ## returns the group delay of the rational IIR filter whose numerator ## has coefficients b and denominator coefficients a. ## ## [g, w] = grpdelay(b,a,n) ## returns the group delay evaluated at n angular frequencies. For fastest ## computation n should factor into a small number of small primes. ## ## [g, w] = grpdelay(b,a,n,'whole') ## evaluates the group delay at n frequencies between 0 and 2*pi. ## ## [g, f] = grpdelay(b,a,n,Fs) ## evaluates the group delay at n frequencies between 0 and Fs/2. ## ## [g, f] = grpdelay(b,a,n,'whole',Fs) ## evaluates the group delay at n frequencies between 0 and Fs. ## ## [g, w] = grpdelay(b,a,w) ## evaluates the group delay at frequencies w (radians per sample). ## ## [g, f] = grpdelay(b,a,f,Fs) ## evaluates the group delay at frequencies f (in Hz). ## ## grpdelay(...) ## plots the group delay vs. frequency. ## ## If the denominator of the computation becomes too small, the group delay ## is set to zero. (The group delay approaches infinity when ## there are poles or zeros very close to the unit circle in the z plane.) ## ## Theory: group delay, g(w) = -d/dw [arg{H(e^jw)}], is the rate of change of ## phase with respect to frequency. It can be computed as: ## ## d/dw H(e^-jw) ## g(w) = ------------- ## H(e^-jw) ## ## where ## H(z) = B(z)/A(z) = sum(b_k z^k)/sum(a_k z^k). ## ## By the quotient rule, ## A(z) d/dw B(z) - B(z) d/dw A(z) ## d/dw H(z) = ------------------------------- ## A(z) A(z) ## Substituting into the expression above yields: ## A dB - B dA ## g(w) = ----------- = dB/B - dA/A ## A B ## ## Note that, ## d/dw B(e^-jw) = sum(k b_k e^-jwk) ## d/dw A(e^-jw) = sum(k a_k e^-jwk) ## which is just the FFT of the coefficients multiplied by a ramp. ## ## As a further optimization when nfft>>length(a), the IIR filter (b,a) ## is converted to the FIR filter conv(b,fliplr(conj(a))). ## For further details, see ## http://ccrma.stanford.edu/~jos/filters/Numerical_Computation_Group_Delay.html function [gd,w] = grpdelay(b,a=1,nfft=512,whole,Fs) if (nargin<1 || nargin>5) print_usage; end HzFlag=0; if length(nfft)>1 if nargin>4 print_usage(); elseif nargin>3 % grpdelay(B,A,F,Fs) Fs = whole; HzFlag=1; else % grpdelay(B,A,W) Fs = 1; end 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=1; whole = ''; end if nargin<3, nfft=512; end if nargin<2, a=1; end else HzFlag=1; end if isempty(nfft), nfft = 512; end if ~strcmp(whole,'whole'), nfft = 2*nfft; end w = Fs*[0:nfft-1]/nfft; end if ~HzFlag, w = w * 2*pi; end oa = length(a)-1; % order of a(z) if oa<0, a=1; oa=0; end % a can be [] ob = length(b)-1; % order of b(z) if ob<0, b=1; ob=0; end % b can be [] as well 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) ## 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; 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 dim. ## @end deftypefn function f=hilbert(f, N = [], dim = []) % ------ PRE: initialization and dimension shifting --------- if (nargin<1 || nargin>3) print_usage; end if ~isreal(f) warning ('HILBERT: ignoring imaginary part of signal'); f = real (f); end 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); end else if (numel(dim)~=1 || ~isnumeric(dim)) error('HILBERT: dim must be a scalar.'); end if rem(dim,1)~=0 error('HILBERT: dim must be an integer.'); end if (dim<1) || (dim>D) error('HILBERT: dim must be in the range from 1 to %d.',D); end end 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.'); end if dim>1 order=[dim, 1:dim-1,dim+1:D]; % Put the desired dimension first. f=permute(f,order); end Ls=size(f,1); % If N is empty it is set to be the length of the transform. if isempty(N) N=Ls; end % 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); end % ------- 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)]; end f=ifft(f); end % ------- POST: Restoration of dimensions ------------ % Restore the original, permuted shape. f=reshape(f,permutedsize); if dim>1 % Undo the permutation. f=ipermute(f,order); end 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/inst/idct.m0000644000000000000000000000445512124117010012534 0ustar 00000000000000## 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; if not, see . ## y = dct (x, n) ## Computes the inverse discrete cosine transform of x. If n is ## given, then x is padded or trimmed to length n before computing ## the transform. If x is a matrix, compute the transform along the ## columns of the the matrix. The transform is faster if x is ## real-valued and even length. ## ## The inverse discrete cosine transform x of X can be defined as follows: ## ## N-1 ## x[n] = sum w(k) X[k] cos (pi (2n+1) k / 2N ), n = 0, ..., N-1 ## k=0 ## ## with w(0) = sqrt(1/N) and w(k) = sqrt(2/N), k = 1, ..., N-1 ## ## See also: idct, dct2, idct2, dctmtx 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/inst/idct2.m0000644000000000000000000000236412124117010012613 0ustar 00000000000000## 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; if not, see . ## y = idct2 (x) ## Computes the inverse 2-D discrete cosine transform of matrix x ## ## y = idct2 (x, m, n) or y = idct2 (x, [m n]) ## Computes the 2-D inverse DCT of x after padding or trimming rows to m and ## columns to n. 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/inst/idst.m0000644000000000000000000000146612124117010012553 0ustar 00000000000000## 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); end end x = dst(y, n) * 2/(n+1); endfunction %!test %! x = log(gausswin(32)); %! assert(x, idst(dst(x)), 100*eps) signal/inst/ifht.m0000644000000000000000000000405212124117010012534 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn{Function File} {m = } ifht ( d, n, dim ) ## @cindex linear algebra ## The function ifht calculates Fast Hartley Transform ## where @var{d} is the real input vector (matrix), and @var{m} ## is the real-transform vector. For matrices 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] = 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(); end if ( nargin == 3 ) Y = ifft(d,n,dim); elseif ( nargin == 2 ) Y = ifft(d,n); else Y = ifft(d); end 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; # end end %!assert(ifht(fht(1:4)),[1 2 3 4]) signal/inst/ifwht.m0000644000000000000000000000473512124117010012733 0ustar 00000000000000## Copyright (C) 2013 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; 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 ## Author: Mike Miller 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/inst/iirlp2mb.m0000644000000000000000000003002712124117010013323 0ustar 00000000000000## 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; 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 tranformation 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/inst/impinvar.m0000644000000000000000000001242512124117010013432 0ustar 00000000000000## 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; 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 specificied, 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 40 (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; % Contstant 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; if not, see . ## usage: [x, t] = impz(b [, a, n, fs]) ## ## Generate impulse-response characteristics of the filter. The filter ## coefficients correspond to the the z-plane rational function with ## numerator b and denominator a. If a is not specified, it defaults to ## 1. If n is not specified, or specified as [], it will be chosen such ## that the signal has a chance to die down to -120dB, or to not explode ## beyond 120dB, or to show five periods if there is no significant ## damping. If no return arguments are requested, plot the results. ## ## See also: freqz, zplane ## TODO: Call equivalent function from control toolbox since it is ## TODO: probably more sophisticated than this one, and since it ## TODO: is silly to maintain two different versions of essentially ## TODO: the same thing. function [x_r, t_r] = impz(b, a = [1], n = [], fs = 1) if nargin == 0 || nargin > 4 print_usage; end 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; end end # 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; end end end n = n + length(b); elseif isempty(n) n = length(b); end if length(a) == 1 x = fftfilt(b/a, [1, zeros(1,n-1)]); else x = filter(b, a, [1, zeros(1,n-1)]); end t = [0:n-1]/fs; if nargout >= 1 x_r = x; end; if nargout >= 2 t_r = t; end; if nargout == 0 unwind_protect title "Impulse Response"; if (fs > 1000) t = t * 1000; xlabel("Time (msec)"); else xlabel("Time (sec)"); end plot(t, x, "^r;;"); unwind_protect_cleanup title ("") xlabel ("") end_unwind_protect end endfunction signal/inst/interp.m0000644000000000000000000000417612124117010013112 0ustar 00000000000000## 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; if not, see . ## usage: y = interp(x, q [, n [, Wc]]) ## ## Upsample the signal x by a factor of q, using an order 2*q*n+1 FIR ## filter. Note that q must be an integer for this rate change method. ## n defaults to 4 and Wc defaults to 0.5. ## ## Example ## # Generate a signal. ## t=0:0.01:2; x=chirp(t,2,.5,10,'quadratic')+sin(2*pi*t*0.4); ## y = interp(x(1:4:length(x)),4,4,1); # interpolate a sub-sample ## stem(t(1:121)*1000,x(1:121),"-g;Original;"); hold on; ## stem(t(1:121)*1000,y(1:121),"-r;Interpolated;"); ## stem(t(1:4:121)*1000,x(1:4:121),"-b;Subsampled;"); hold off; ## ## See also: decimate, resample 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/inst/invfreq.m0000644000000000000000000002075012124117010013257 0ustar 00000000000000%% 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; 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 %% TODO: implement Steiglitz-McBride iterations %% TODO: improve numerical stability for high order filters (matlab is a bit better) %% TODO: 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; end n = max(nA, nB); m = n+1; mA = nA+1; mB = nB+1; nF = length(F); if nF ~= length(H), disp('invfreqz: length of H and F must be the same'); end; if nargin < 5 || isempty(W), W = ones(1, nF); end; if nargin < 6, iter = []; end if nargin < 7 tol = []; end if nargin < 8 || isempty(tr), tr = ''; end if nargin < 9, plane = 'z'; end if nargin < 10, varargin = {}; end if iter~=[], disp('no implementation for iter yet'),end if tol ~=[], disp('no implementation for tol yet'),end if (plane ~= 'z' && plane ~= 's'), disp('invfreqz: Error in plane argument'), end [reg, prop ] = parseparams(varargin); %# should we normalise 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 end 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'); end otherwise %# FIXME: just skip it for now disp(sprintf("Ignoring unkown argument %s", varargin{indi})); indi = indi + 1; end end end 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(' ') end 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; end s = exp(-s); case 's' if max(F) > 1e6 && n > 5, if ~norm, disp('Be carefull, 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; end end end 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)); end; 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; end for k = 1+min(nA, nB):max(nA, nB)-1, if k <= nB, Rr(:, 1+k) = Zk; end if k <= nA, Rr(:, mB+k) = -Zk.*H; end Zk = Zk.*s; end k = k+1; if k <= nB, Rr(:, 1+k) = Zk; end if k <= nA, Rr(:, mB+k) = -Zk.*H; end %# 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); end 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 normalised -- unscale coefficients Zk = Fmax.^[n:-1:0].'; for k = nB:-1:1+zB, B(k) = B(k)/Zk(k); end for k = nA:-1:1, A(k) = A(k)/Zk(k); end end end 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); %! xlabel("Frequency (rad/sample)"); %! ylabel("Magnitude"); %! plot(w,[abs(H), abs(Hh)]) %! legend('Original','Measured'); %! err = norm(H-Hh); %! disp(sprintf('L2 norm of frequency response error = %f',err)); signal/inst/invfreqs.m0000644000000000000000000000627712124117010013452 0ustar 00000000000000%% 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; 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)); % TODO: 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)); end end end end end % 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); %! xlabel("Frequency (rad/sec)"); %! ylabel("Magnitude"); %! plot(w,[abs(H0); abs(Hh)]) %! legend('Original','Measured'); %! err = norm(H0-Hh); %! disp(sprintf('L2 norm of frequency response error = %f',err)); signal/inst/invfreqz.m0000644000000000000000000000601512124117010013447 0ustar 00000000000000%% 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; 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 frequncy (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))); %% TODO: 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)); end end end end end % 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); %! xlabel("Frequency (rad/sample)"); %! ylabel("Magnitude"); %! plot(w,[abs(H0) abs(Hh)]) %! legend('Original','Measured'); %! err = norm(H0-Hh); %! disp(sprintf('L2 norm of frequency response error = %f',err)); signal/inst/invimpinvar.m0000644000000000000000000001262412124117010014150 0ustar 00000000000000## 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; 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 specificied, 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/inst/kaiser.m0000644000000000000000000000336312124117010013064 0ustar 00000000000000## 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; if not, see . ## usage: kaiser (L, beta) ## ## Returns the filter coefficients of the L-point Kaiser window with ## parameter beta. ## ## For the definition of the Kaiser window, see A. V. Oppenheim & ## R. W. Schafer, "Discrete-Time Signal Processing". ## ## The continuous version of width L centered about x=0 is: ## ## besseli(0, beta * sqrt(1-(2*x/L).^2)) ## k(x) = -------------------------------------, L/2 <= x <= L/2 ## besseli(0, beta) ## ## See also: kaiserord function w = kaiser (L, beta = 0.5) if (nargin < 1) print_usage; elseif !(isscalar (L) && (L == round (L)) && (L > 0)) error ("kaiser: L has to be a positive integer"); elseif !(isscalar (beta) && (beta == real (beta))) error ("kaiser: beta has to be a real scalar"); endif if (L == 1) w = 1; else m = L - 1; k = (0 : m)'; k = 2 * beta / m * sqrt (k .* (m - k)); w = besseli (0, k) / besseli (0, beta); endif endfunction %!demo %! % use demo("kaiserord"); signal/inst/kaiserord.m0000644000000000000000000001333012124117010013564 0ustar 00000000000000## 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; if not, see . ## usage: [n, Wn, beta, ftype] = kaiserord(f, m, dev [, fs]) ## ## Returns the parameters needed for fir1 to produce a filter of the ## desired specification from a kaiser window: ## n: order of the filter (length of filter minus 1) ## Wn: band edges for use in fir1 ## beta: parameter for kaiser window of length n+1 ## ftype: choose between pass and stop bands ## b = fir1(n,Wn,kaiser(n+1,beta),ftype,'noscale'); ## ## f: frequency bands, given as pairs, with the first half of the ## first pair assumed to start at 0 and the last half of the last ## pair assumed to end at 1. It is important to separate the ## band edges, since narrow transition regions require large order ## filters. ## m: magnitude within each band. Should be non-zero for pass band ## and zero for stop band. All passbands must have the same ## magnitude, or you will get the error that pass and stop bands ## must be strictly alternating. ## dev: deviation within each band. Since all bands in the resulting ## filter have the same deviation, only the minimum deviation is ## used. In this version, a single scalar will work just as well. ## fs: sampling rate. Used to convert the frequency specification into ## the [0, 1], where 1 corresponds to the Nyquist frequency, fs/2. ## ## The Kaiser window parameters n and beta are computed from the ## relation between ripple (A=-20*log10(dev)) and transition width ## (dw in radians) discovered empirically by Kaiser: ## ## / 0.1102(A-8.7) A > 50 ## beta = | 0.5842(A-21)^0.4 + 0.07886(A-21) 21 <= A <= 50 ## \ 0.0 A < 21 ## ## n = (A-8)/(2.285 dw) ## ## Example ## [n, w, beta, ftype] = kaiserord([1000,1200], [1,0], [0.05,0.05], 11025); ## freqz(fir1(n,w,kaiser(n+1,beta),ftype,'noscale'),1,[],11025); ## TODO: order is underestimated for the final test case: 2 stop bands. ## TODO: octave> ftest("kaiserord") # shows test cases 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. %!# XXX FIXME XXX extend demo to show detail at criteria box corners signal/inst/levinson.m0000644000000000000000000000616612124117010013447 0ustar 00000000000000## 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; if not, see . ## usage: [a, v, ref] = levinson (acf [, p]) ## ## Use the Durbin-Levinson algorithm to solve: ## toeplitz(acf(1:p)) * x = -acf(2:p+1). ## The solution [1, x'] is the denominator of an all pole filter ## approximation to the signal x which generated the autocorrelation ## function acf. ## ## acf is the autocorrelation function for lags 0 to p. ## p defaults to length(acf)-1. ## Returns ## a=[1, x'] the denominator filter coefficients. ## v= variance of the white noise = square of the numerator constant ## ref = reflection coefficients = coefficients of the lattice ## implementation of the filter ## Use freqz(sqrt(v),a) to plot the power spectrum. ## ## REFERENCE ## [1] Steven M. Kay and Stanley Lawrence Marple Jr.: ## "Spectrum analysis -- a modern perspective", ## Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981 ## Based on: ## yulewalker.m ## Copyright (C) 1995 Friedrich Leisch ## GPL license ## TODO: Matlab doesn't return reflection coefficients and ## TODO: errors in addition to the polynomial a. ## TODO: What is the difference between aryule, levinson, ## TODO: 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/inst/marcumq.m0000644000000000000000000004237112124117010013255 0ustar 00000000000000## 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; 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(); end if ( any(a<0) || any(b<0) ) error("Parameters to marcumq must be positive"); end if ( any(M<0) || any(floor(M)~=M) ) error("M must be a positive integer"); end [a,b,M] = tablify(a,b,M); Q = arrayfun(@mq, a,b,M,tol); end % 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; end if (a==0) k = 0:(M-1); Q = exp(-b^2/2)*sum(b.^(2*k)./(2.^k .* factorial(k))); N = 0; return; end % The basic iteration. If a1 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.000000]; %! %! 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.000000]; %! %! 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.000000]; %! %! 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/inst/mexihat.m0000644000000000000000000000211012124117010013232 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{psi,x}] =} mexihat(@var{lb,ub,n}) ## Compute the Mexican hat wavelet. ## @end deftypefn function [psi,x] = mexihat(lb,ub,n) if (nargin < 3); print_usage; end 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/inst/meyeraux.m0000644000000000000000000000173212124117010013443 0ustar 00000000000000## 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; 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; end y = 35.*x.^4-84.*x.^5+70.*x.^6-20.*x.^7; endfunction signal/inst/morlet.m0000644000000000000000000000205212124117010013102 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{psi,x}] =} morlet(@var{lb,ub,n}) ## Compute the Morlet wavelet. ## @end deftypefn function [psi,x] = morlet(lb,ub,n) if (nargin < 3); print_usage; end 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/inst/movingrms.m0000644000000000000000000000562412124117010013631 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{rmsx},@var{w}] =} movingrms (@var{x},@var{w},@var{rc},@var{Fs}=1) ## Calculates moving RMS value of the signal in @var{x}. ## ## The signla is convoluted against a sigmoid window of width @var{w} and risetime ## @var{rc}. The units of these to parameters are relative ot the vlaue 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); end 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); %! %! close all %! figure () %! %! 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); %! %! close all %! figure () %! %! 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/inst/mscohere.m0000644000000000000000000000333512124117010013412 0ustar 00000000000000%% 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; if not, see . %% Usage: %% [Pxx,freq]=mscohere(x,y,window,overlap,Nfft,Fs,range) %% %% Estimate (mean square) coherence of signals "x" and "y". %% Use the Welch (1967) periodogram/FFT method. %% See "help pwelch" for description of arguments, hints and references function [varargout] = mscohere(varargin) %% %% Check fixed argument if (nargin < 2 || nargin > 7) print_usage (); end 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} = []; end end 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; end end signal/inst/ncauer.m0000644000000000000000000000637612124117010013072 0ustar 00000000000000## 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; 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); end for m=1 : 30 sig02=sig02+(-1)^m * q^(m^2) * cosh(2*m*l); end 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; end # wi=zeros(1,r); for ii=1 : r if rem(n,2) mu=ii; else mu=ii-1/2; end 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)); end soma2=0; for m=1 : 30 soma2 = soma2 + 2*((-1)^m * q^(m^2) * cos((2*m*pi*mu)/n)); end wi(ii)=(soma1/(1+soma2)); end # 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); end ##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]; end ## 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/inst/nuttallwin.m0000644000000000000000000000256212124117010014007 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{w}] =} nuttallwin(@var{L}) ## Compute the Blackman-Harris window defined by Nuttall of length L. ## @seealso{blackman, blackmanharris} ## @end deftypefn function [w] = nuttallwin(L) if (nargin != 1); print_usage; end if(L < 0) error('L must be positive'); end if(L ~= floor(L)) L = round(L); warning('L rounded to the nearest integer.'); end if (L == 1) w = 1; else N = L-1; a0 = 0.355768; a1 = 0.487396; a2 = 0.144232; a3 = 0.012604; n = -N/2:N/2; w = a0 + a1.*cos(2.*pi.*n./N) + a2.*cos(4.*pi.*n./N) + a3.*cos(6.*pi.*n./N); w = w'; endif endfunction signal/inst/parzenwin.m0000644000000000000000000000245312124117010013622 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{w}] =} parzenwin(@var{L}) ## Compute the Parzen window of lenght L. ## @seealso{rectwin, bartlett} ## @end deftypefn function w = parzenwin (L) if(nargin != 1) print_usage; elseif(L < 0) error('L must be positive'); end if(L ~= floor(L)) L = round(L); end N = L-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)./(L/2)).^2 + 6*(abs(n1)./(L/2)).^3; w2 = 2.*(1-abs(n2)./(L/2)).^3; w3 = 2.*(1-abs(n3)./(L/2)).^3; w = [w3 w1 w2]'; endfunction signal/inst/pburg.m0000644000000000000000000001455712124117010012734 0ustar 00000000000000%% 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; 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). Recognised 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"' ); end 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={}; end end end %% [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{:}); end end %!demo %! fflush(stdout); %! rand('seed',2038014164); %! a = [ 1.0 -1.6216505 1.1102795 -0.4621741 0.2075552 -0.018756746 ]; %! signal = detrend(filter(0.70181,a,rand(1,16384))); %! % frequency shift by modulating with exp(j.omega.t) %! skewed = signal.*exp(2*pi*i*2/25*[1:16384]); %! Fs = 25; %! hold on %! pburg(signal,3,[],Fs); %! input('Onesided 3-pole spectrum. Press ENTER', 's' ); %! pburg(signal,4,[],Fs,'whole'); %! input('Twosided 4-pole spectrum of same data. Press ENTER', 's' ); %! pburg(signal,5,128,Fs,'shift', 'semilogy'); %! input('Twosided, centred zero-frequency, 5-pole. Press ENTER', 's' ); %! pburg(skewed,7,128,Fs,'AKICc','shift','semilogy'); %! input('Complex data, AKICc chooses no. of poles. Press ENTER', 's' ); %! user_freq=[-0.2:0.02:0.2]*Fs; %! pburg(skewed,7,user_freq,Fs,'AKICc','semilogy'); %! input('User-specified frequency values. Press ENTER', 's' ); %! hold off %! clf signal/inst/pei_tseng_notch.m0000644000000000000000000001036412124117010014755 0ustar 00000000000000## 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; 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 ## TODO: 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 (:)'; ##Normalise appropriately frequencies *= pi; bandwidths *= pi; M2 = 2 * length ( frequencies ); ##Splice centre and offset frequencies ( Equation 11 ) omega = vec ( [ frequencies - bandwidths / 2; frequencies ] ); ##Splice centre 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/inst/polystab.m0000644000000000000000000000201612124117010013435 0ustar 00000000000000## 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; if not, see . ## b = polystab(a) ## ## Stabalize 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/inst/private/__fwht_opts__.m0000644000000000000000000000450612124117010016071 0ustar 00000000000000## Copyright (C) 2013 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; 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 ## Author: Mike Miller 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 (idx_bin) + 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/inst/private/h1_z_deriv.m0000644000000000000000000000431612124117010015311 0ustar 00000000000000## 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; if not, see . ## Adapted by Carnë Draug on 2011 ## This function is necessary for impinvar and invimpinvar of the signal package ## 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/inst/private/inv_residue.m0000644000000000000000000000412412124117010015570 0ustar 00000000000000## 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; if not, see . ## Adapted by Carnë Draug on 2011 ## This function is necessary for impinvar and invimpinvar of the signal package ## 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 contstant 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; if not, see . ## Adapted by Carnë Draug on 2011 ## This function is necessary for impinvar and invimpinvar of the signal package ## Reverse the coefficients of a polynomial function p_out = polyrev (p_in) p_out = p_in(end:-1:1); endfunction signal/inst/private/to_real.m0000644000000000000000000000173412124117010014705 0ustar 00000000000000## 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; if not, see . ## Adapted by Carnë Draug on 2011 ## This function is necessary for impinvar and invimpinvar of the signal package ## 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/inst/pulstran.m0000644000000000000000000001255612124117010013462 0ustar 00000000000000## 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; if not, see . ## usage: y=pulstran(t,d,'func',...) ## y=pulstran(t,d,p,Fs,'interp') ## ## Generate the signal y=sum(func(t+d,...)) for each d. If d is a ## matrix of two columns, the first column is the delay d and the second ## column is the amplitude a, and y=sum(a*func(t+d)) for each d,a. ## Clearly, func must be a function which accepts a vector of times. ## Any extra arguments needed for the function must be tagged on the end. ## ## Example ## fs = 11025; # arbitrary sample rate ## f0 = 100; # pulse train sample rate ## w = 0.001; # pulse width of 1 millisecond ## auplot(pulstran(0:1/fs:0.1, 0:1/f0:0.1, 'rectpuls', w), fs); ## ## If instead of a function name you supply a pulse shape sampled at ## frequency Fs (default 1 Hz), an interpolated version of the pulse ## is added at each delay d. The interpolation stays within the the ## time range of the delayed pulse. The interpolation method defaults ## to linear, but it can be any interpolation method accepted by the ## function interp1. ## ## Example ## fs = 11025; # arbitrary sample rate ## f0 = 100; # pulse train sample rate ## w = boxcar(10); # pulse width of 1 millisecond at 10 kHz ## auplot(pulstran(0:1/fs:0.1, 0:1/f0:0.1, w, 10000), fs); ## TODO: Make it faster. It is currently unusable for anything real. ## TODO: It may not be possible to speed it up with the present interface. ## TODO: 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); title("rectpuls"); %! auplot(pulstran(t', d', 'rectpuls', w), fs); %! hold on; plot(d*1000,ones(size(d)),'g*;pulse;'); hold off; %! %! subplot(223); title("sinc => band limited interpolation"); %! auplot(pulstran(f0*t, [f0*d', a], 'sinc'), fs); %! hold on; plot(d*1000,a,'g*;pulse;'); hold off; %! %! subplot(222); title("interpolated boxcar"); %! pulse = boxcar(30); # pulse width of 3 ms at 10 kHz %! auplot(pulstran(t, d', pulse, 10000), fs); %! hold on; plot(d*1000,ones(size(d)),'g*;pulse;'); hold off; %! %! subplot(224); title("interpolated asymmetric sin"); %! pulse = sin(2*pi*[0:0.0001:w]/w).*[w:-0.0001:0]; %! auplot(pulstran(t', [d', a], pulse', 10000), fs); %! hold on; plot(d*1000,a*w,'g*;pulse;'); hold off; title(""); %! %! %---------------------------------------------------------- %! % Should see (1) rectangular pulses centered on *, %! % (2) rectangular pulses to the right of *, %! % (3) smooth interpolation between the *'s, and %! % (4) asymetric sines to the right of * signal/inst/pwelch.m0000644000000000000000000011524012124117010013066 0ustar 00000000000000%% 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; 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 behaviour %% is to remove the mean. However, the matlab pwelch does not do this. %% 6) WARNING ON CONFIDENCE INTERVALS %% Confidence intervals are obtained by measuring the sample variance of %% the periodograms and assuming that the periodograms have a Gaussian %% probability distribution. This assumption is not accurate. If, for %% example, the data (x) is Gaussian, the periodogram has a Rayleigh %% distribution. However, the confidence intervals may still be useful. %% %% 7) COMPATIBILITY WITH Matlab R11, R12, etc %% When used without the second data (y) argument, arguments are compatible %% with the pwelch of Matlab R12, R13, R14, 2006a and 2006b except that %% 1) overlap is expressed as a multiple of window length --- %% effect of overlap scales with window length %% 2) default values of length(window), Nfft and Fs are more sensible, and %% 3) Goertzel algorithm is not available so Nfft cannot be an array of %% frequencies as in Matlab 2006b. %% Pwelch has four persistent Matlab-compatibility levels. Calling pwelch %% with an empty first argument sets the order of arguments and defaults %% specified above in the USAGE and ARGUMENTS section of this documentation. %% prev_compat=pwelch([]); %% [Pxx,f]=pwelch(x,window,overlap,Nfft,Fs,conf,...); %% Calling pwelch with a single string argument (as described below) gives %% compatibility with Matlab R11 or R12, or the R14 spectrum.welch %% defaults. The returned value is the PREVIOUS compatibility string. %% %% Matlab R11: For compatibility with the Matlab R11 pwelch: %% prev_compat=pwelch('R11-'); %% [Pxx,f]=pwelch(x,Nfft,Fs,window,overlap,conf,range,units); %% %% units of overlap are "number of samples" %% %% defaults: Nfft=min(length(x),256), Fs=2*pi, length(window)=Nfft, %% %% window=Hanning, do not detrend, %% %% N.B. "Sloppy" is not available. %% %% Matlab R12: For compatibility with Matlab R12 to 2006a pwelch: %% prev_compat=pwelch('R12+'); %% [Pxx,f]=pwelch(x,window,overlap,nfft,Fs,...); %% %% units of overlap are "number of samples" %% %% defaults: length(window)==length(x)/8, window=Hamming, %% %% Nfft=max(256,NextPow2), Fs=2*pi, do not detrend %% %% NextPow2 is the next power of 2 greater than or equal to the %% %% window length. "Sloppy", "conf" are not available. Default %% %% window length gives very poor amplitude resolution. %% %% To adopt defaults of the Matlab R14 "spectrum.welch" spectrum object %% associated "psd" method. %% prev_compat=pwelch('psd'); %% [Pxx,f] = pwelch(x,window,overlap,Nfft,Fs,conf,...); %% %% overlap is expressed as a percentage of window length, %% %% defaults: length(window)==64, Nfft=max(256,NextPow2), Fs=2*pi %% %% do not detrend %% %% NextPow2 is the next power of 2 greater than or equal to the %% %% window length. "Sloppy" is not available. %% %% Default window length gives coarse frequency resolution. %% %% %% REFERENCES %% [1] Peter D. Welch (June 1967): %% "The use of fast Fourier transform for the estimation of power spectra: %% a method based on time averaging over short, modified periodograms." %% IEEE Transactions on Audio Electroacoustics, Vol AU-15(6), pp 70-73 %% %% [2] William H. Press and Saul A. Teukolsky and William T. Vetterling and %% Brian P. Flannery", %% "Numerical recipes in C, The art of scientific computing", 2nd edition, %% Cambridge University Press, 2002 --- Section 13.7. %% [3] Paul Kienzle (1999-2001): "pwelch", http://octave.sourceforge.net/ 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; end 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' ); end %% 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(:); end %% %% 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.' ); end %% force COLUMN vector y = varargin{1}(:); arg2_is_y = 1; break; end end %% %% 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; end elseif ( strcmp(arg, 'cross' ) ) if ( ~do_cross ) n_results = n_results+1; do_cross = n_results; end elseif ( strcmp(arg, 'trans' ) ) if ( ~do_trans ) n_results = n_results+1; do_trans = n_results; end elseif ( strcmp(arg, 'coher' ) ) if ( ~do_coher ) n_results = n_results+1; do_coher = n_results; end elseif ( strcmp(arg, 'ypower' ) ) if ( ~do_ypower ) n_results = n_results+1; do_ypower = n_results; end else error( 'pwelch: string arg %d illegal value: %s', iarg+1, arg ); end %% 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' ); end %% %% 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; end %% %% -- "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; end %% %% 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(:); end else is_win = 0; end 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); end 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 ); end 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 ); end Nfft = arg; %% else error( 'pwelch: arg %d must be string', iarg+1 ); end end if ( conf>0 && (n_results && ~do_power ) ) error('pwelch: can give confidence interval for x power spectrum only' ); end %% %% 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; end 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 ); end 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; end %% make Hann window (don't depend on sigproc) xx = seg_len - 1; window = 0.5 - 0.5 * cos( (2*pi/xx)*[0:xx].' ); end %% %% 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 ); end %% make Hamming window (don't depend on sigproc) xx = seg_len - 1; window = 0.54 - 0.46 * cos( (2*pi/xx)*[0:xx].' ); end if ( isempty(Nfft) ) Nfft = max( 256, 2^ceil(log(seg_len)*nearly_one/log_two) ); end %% %% 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; end %% make Hamming window (don't depend on sigproc) xx = seg_len - 1; window = 0.54 - 0.46 * cos( (2*pi/xx)*[0:xx].' ); end %% Now we know segment length, %% so we can set default overlap as number of samples if ( ~isempty(overlap) ) overlap = fix(seg_len * overlap / 100 ); end if ( isempty(Nfft) ) Nfft = max( 256, 2^ceil(log(seg_len)*nearly_one/log_two) ); end %% %% 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; end seg_len = 2 ^ ceil( log(sqrt(x_len/(1-overlap)))*nearly_one/log_two ); end %% make Hamming window (don't depend on sigproc) xx = seg_len - 1; window = 0.54 - 0.46 * cos( (2*pi/xx)*[0:xx].' ); end %% Now we know segment length, %% so we can set default overlap as number of samples if ( ~isempty(overlap) ) overlap = fix(seg_len * overlap); end %% %% calculate FFT length if ( isempty(Nfft) ) Nfft = seg_len; end if ( is_sloppy ) Nfft = 2 ^ ceil( log(Nfft) * nearly_one / log_two ); end end %% end of compatibility options %% %% minimum FFT length is seg_len Nfft = max( Nfft, seg_len ); %% Mean square of window is required for normalising 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 = []; end 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); end fft_x = fft(xx); end 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); end fft_y = fft(yy); end 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; end end if ( need_Pxy ) %% Pxy (cross power spectrum) is complex. Do not force to be real. Pxy = Pxy + fft_y .* conj(fft_x); end if ( need_Pyy ) %% force Pyy to be real Pyy = Pyy + real(fft_y .* conj(fft_y)); end n_ffts = n_ffts +1; end %% %% 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); end end %% %% 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]; end end if ( need_Pxy ) Pxy = Pxy(1:psd_len) + conj([0; Pxy(Nfft:-1:psd_len+1); 0]); end if ( need_Pyy ) Pyy = Pyy(1:psd_len) + [0; Pyy(Nfft:-1:psd_len+1); 0]; end 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)]; end end if ( need_Pxy ) Pxy = Pxy(1:psd_len) + conj([0; Pxy(Nfft:-1:psd_len+1)]); end if ( need_Pyy ) Pyy = Pyy(1:psd_len) + [0; Pyy(Nfft:-1:psd_len+1)]; end end else %% two-sided (and shifted) psd_len = Nfft; end %% 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; end end if ( do_cross ) spectra(:,do_cross) = Pxy / scale; spect_type(do_cross) = 2; end if ( do_trans ) spectra(:,do_trans) = Pxy ./ Pxx; spect_type(do_trans) = 3; end if ( do_coher ) %% force coherence to be real spectra(:,do_coher) = real(Pxy .* conj(Pxy)) ./ Pxx ./ Pyy; spect_type(do_coher) = 4; end if ( do_ypower ) spectra(:,do_ypower) = Pyy / scale; spect_type(do_ypower) = 5; end 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,:)]; end end %% %% RETURN RESULTS or PLOT if ( nargout>=2 && conf>0 ) varargout{2} = Vxx; end if ( nargout>=(2+(conf>0)) ) %% frequency is 2nd or 3rd return value, %% depends on if 2nd is confidence interval varargout{2+(conf>0)} = freq; end 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 = []; end if ( n_results > 1 ) figure(); end 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))]); end 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))); end title( char(plot_title(spect_type(ii),:)) ); ylabel( 'phase' ); end end %for end end end %!demo %! fflush(stdout); %! rand('seed',2038014164); %! 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]); %! Fs = 25; % sampling frequency %! hold off %! pwelch([]); %! pwelch(signal); %! disp('Default settings: Fs=1Hz, overlap=0.5, no padding' ) %! input('Onesided power spectral density (real data). Press ENTER', 's' ); %! hold on %! pwelch(skewed); %! disp('Frequency-shifted complex data. Twosided wrap-around spectrum.' ); %! input('Area is same as one-sided spectrum. Press ENTER', 's' ); %! pwelch(signal,'shift','semilogy'); %! input('Twosided, centred zero-frequency, lin-log plot. Press ENTER', 's' ); %! hold off %! figure(); %! pwelch(skewed,[],[],[],Fs,'shift','semilogy'); %! input('Actual Fs=25 Hz. Note change of scales. Press ENTER', 's' ); %! pwelch(skewed,[],[],[],Fs,0.95,'shift','semilogy'); %! input('Spectral density with 95% confidence interval. Press ENTER', 's' ); %! pwelch('R12+'); %! pwelch(signal,'squared'); %! input('Spectral density with Matlab R12 defaults. Press ENTER', 's' ); %! figure(); %! pwelch([]); %! pwelch(signal,3640,[],4096,2*pi,[],'no-strip'); %! input('Same spectrum with 95% confidence interval. Press ENTER', 's' ); %! figure(); %! pwelch(signal,[],[],[],2*pi,0.95,'no-strip'); %! input('95% confidence interval with native defaults. Press ENTER', 's' ); %! pwelch(signal,64,[],[],2*pi,'no-strip'); %! input('Only 32 frequency values in this spectrum. Press ENTER', 's' ); %! hold on %! pwelch(signal,64,[],256,2*pi,'no-strip'); %! input('4:1 zero padding gives artificial smoothing. Press ENTER', 's' ); %! figure(); %! pwelch('psd'); %! pwelch(signal,'squared'); %! input('Just like Matlab spectrum.welch(...) defaults. Press ENTER', 's' ); %! hold off %! pwelch({}); %! pwelch(white,signal,'trans','coher','short') %! input('Transfer and coherence functions. Press ENTER', 's' ); %! disp('Use "close all" to remove plotting windows.' ); signal/inst/pyulear.m0000644000000000000000000001240012124117010013257 0ustar 00000000000000%% 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; 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"' ); end %% [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{:}); end end %!demo %! fflush(stdout); %! rand('seed',2038014164); %! a = [ 1.0 -1.6216505 1.1102795 -0.4621741 0.2075552 -0.018756746 ]; %! signal = detrend(filter(0.70181,a,rand(1,16384))); %! % frequency shift by modulating with exp(j.omega.t) %! skewed = signal.*exp(2*pi*i*2/25*[1:16384]); %! Fs = 25; %! hold on %! pyulear(signal,3,[],Fs); %! disp( 'Results from this demo should be nearly the same as pburg demo' ); %! input('Onesided 3-pole spectrum. Press ENTER', 's' ); %! pyulear(signal,4,[],Fs,'whole'); %! input('Twosided 4-pole spectrum of same data. Press ENTER', 's' ); %! pyulear(signal,5,128,Fs,'shift', 'semilogy'); %! input('Twosided, centred zero-frequency, 5-pole. Press ENTER', 's' ); %! pyulear(skewed,7,128,Fs,'shift','semilogy'); %! input('Complex data, frequency-shifted. Press ENTER', 's' ); %! user_freq=[-0.2:0.02:0.2]*Fs; %! pyulear(skewed,7,user_freq,Fs,'semilogy'); %! input('User-specified frequency values. Press ENTER', 's' ); %! hold off %! clf signal/inst/qp_kaiser.m0000644000000000000000000000527212124117010013565 0ustar 00000000000000## 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; if not, see . ## Usage: qp_kaiser (nb, at, linear) ## ## Computes a finite impulse response (FIR) filter for use with a ## quasi-perfect reconstruction polyphase-network filter bank. This ## version utilizes a Kaiser window to shape the frequency response of ## the designed filter. Tha number nb of bands and the desired ## attenuation at in the stop-band are given as parameters. ## ## The Kaiser window is multiplied by the ideal impulse response ## h(n)=a.sinc(a.n) and converted to its minimum-phase version by means ## of a Hilbert transform. ## ## By using a third non-null argument, the minimum-phase calculation is ## ommited at all. 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/inst/rceps.m0000644000000000000000000000767512124117010012734 0ustar 00000000000000## 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; if not, see . ## usage: [y, xm] = rceps(x) ## Produce the cepstrum of the signal x, and if desired, the minimum ## phase reconstruction of the signal x. If x is a matrix, do so ## for each column of the matrix. ## ## Example ## f0=70; Fs=10000; # 100 Hz fundamental, 10kHz sampling rate ## a=poly(0.985*exp(1i*pi*[0.1, -0.1, 0.3, -0.3])); # two formants ## s=0.005*randn(1024,1); # Noise excitation signal ## s(1:Fs/f0:length(s)) = 1; # Impulse glottal wave ## x=filter(1,a,s); # Speech signal in x ## [y, xm] = rceps(x.*hanning(1024)); # cepstrum and min phase reconstruction ## ## Reference ## Programs for digital signal processing. IEEE Press. ## New York: John Wiley & Sons. 1979. function [y, ym] = rceps(x) if (nargin != 1) print_usage; end 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:n/2+1), zeros(1,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:n/2+1,:); zeros(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 %!error rceps %!error rceps(1,2) # too many arguments %!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 %! #XXX FIXME XXX 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.'); %! tol = 1e-14; %! assert(yt.', y, tol); %! assert(xmt.', xm, tol); %% 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)); %!demo %! f0=70; Fs=10000; # 100 Hz fundamental, 10kHz 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); %! auplot(x,Fs,'b',';signal;'); %! hold on; auplot(xm,Fs,'g',';reconstruction;'); %! hold off; %! subplot(312); %! axis("ticy"); %! plot(w,log(abs(hx)), ";magnitude;", ... %! w,log(abs(hxm)),";reconstruction;"); %! subplot(313); %! axis("on"); %! plot(w,unwrap(arg(hx))/(2*pi), ";phase;",... %! w,unwrap(arg(hxm))/(2*pi),";reconstruction;"); %! figure(2); auplot(y,Fs,';cepstrum;'); %! %------------------------------------------------------------- %! % 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/inst/rectpuls.m0000644000000000000000000000366412124117010013453 0ustar 00000000000000## 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; if not, see . ## usage: y = rectpuls(t, w) ## ## Generate a rectangular pulse over the interval [-w/2,w/2), sampled at ## times t. This is useful with the function pulstran for generating a ## series pulses. ## ## Example ## fs = 11025; # arbitrary sample rate ## f0 = 100; # pulse train sample rate ## w = 0.3/f0; # pulse width 3/10th the distance between pulses ## auplot(pulstran(0:1/fs:4/f0, 0:1/f0:4/f0, 'rectpuls', w), fs); ## ## See also: pulstran function y = rectpuls(t, w = 1) if nargin<1 || nargin>2, print_usage; endif y = zeros(size(t)); idx = find(t>=-w/2 & t < w/2); try wfi = warning("off", "Octave:fortran-indexing"); catch wfi = 0; end unwind_protect y(idx) = ones(size(idx)); unwind_protect_cleanup warning(wfi); end_unwind_protect endfunction %!assert(rectpuls(0:1/100:0.3,.1), rectpuls([0:1/100:0.3]',.1)'); %!assert(isempty(rectpuls([],.1))); %!demo %! fs = 11025; # arbitrary sample rate %! f0 = 100; # pulse train sample rate %! w = 0.3/f0; # pulse width 1/10th the distance between pulses %! ylabel("amplitude"); xlabel("time (ms)"); %! title("graph shows 3 ms pulses at 0,10,20,30 and 40 ms"); %! auplot(pulstran(0:1/fs:4/f0, 0:1/f0:4/f0, 'rectpuls', w), fs); %! title(""); xlabel(""); ylabel(""); signal/inst/rectwin.m0000644000000000000000000000176412124117010013264 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{w}] =} rectwin(@var{L}) ## Return the filter coefficients of a rectangle window of length L. ## @seealso{hamming, hanning} ## @end deftypefn function w = rectwin(L) if (nargin < 1); print_usage; end w = ones(round(L),1); endfunction signal/inst/resample.m0000644000000000000000000001170712124117010013417 0ustar 00000000000000## 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; 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=p/great_common_divisor; q=q/great_common_divisor; endif ## filter design if required if (nargin < 4) ## properties of the antialiasing filter log10_rejection = -3.0; stopband_cutoff_f = 1.0/(2.0 * 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; 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 (@code{residued}) 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)}. %% Say @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 %% Say @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; 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)}. %% Say @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 %% Say @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"); end 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)); end end %!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/inst/sampled2continuous.m0000644000000000000000000000254212124117010015442 0ustar 00000000000000## 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; if not, see . ## Usage: ## ## xt = sampled2continuous( xn , T, t ) ## ## Calculate the x(t) reconstructed ## from samples x[n] sampled at a rate 1/T samples ## per unit time. ## ## t is all the instants of time when you need x(t) ## from x[n]; this time is relative to x[0] and not ## an absolute time. ## ## This function can be used to calculate sampling rate ## effects on aliasing, actual signal reconstruction ## from discrete samples. 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 end signal/inst/sawtooth.m0000644000000000000000000000376212124117010013461 0ustar 00000000000000## 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; 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/inst/schtrig.m0000644000000000000000000000474112124117010013252 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{rmsx},@var{w}] =} schtrig (@var{x},@var{lvl},@var{rst}=1) ## Implements a multisignal Schmitt trigger with levels @var{lvl}. ## ## The triger works along the first dimension of the array @var{x}. When @code{@var{rst}==1} ## the state of the trigger for all signals is set to the low state (i.e. 0). ## ## Run @code{demo schtrig} to see an example. ## ## @seealso{clustersegment} ## @end deftypefn function v = schtrig (x, lvl, rst = 1) persistent st0; if length(lvl) == 1 lvl = abs (lvl)*[1 -1]; else lvl = sort(lvl,'descend'); end [nT nc] = size(x); v = NA (nT, nc); if rst || isempty(st0) st0 = zeros(1,nc); printf ("Trigger initialized!\n"); flush (stdout); end 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'); for i=1:nc % Record the state at the begining 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); end end end 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); %! %! h = plot(t,x,t,v); %! set (h([1 3]),'color','b'); %! set (h([2 4]),'color',[0 1 0.5]); %! set (h,'linewidth',2); %! line([0; 1],lvl([1; 1]),'color','r'); %! line([0;1],lvl([2;2]),'color','b') signal/inst/sftrans.m0000644000000000000000000001676012124117010013273 0ustar 00000000000000## 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; if not, see . ## usage: [Sz, Sp, Sg] = sftrans(Sz, Sp, Sg, W, stop) ## ## Transform band edges of a generic lowpass filter (cutoff at W=1) ## represented in splane zero-pole-gain form. W is the edge of the ## target filter (or edges if band pass or band stop). Stop is true for ## high pass and band stop filters or false for low pass and band pass ## filters. Filter edges are specified in radians, from 0 to pi (the ## nyquist frequency). ## ## Theory: Given a low pass filter represented by poles and zeros in the ## splane, you can convert it to a low pass, high pass, band pass or ## band stop by transforming each of the poles and zeros individually. ## The following table summarizes the transformation: ## ## Transform Zero at x Pole at x ## ---------------- ------------------------- ------------------------ ## Low Pass zero: Fc x/C pole: Fc x/C ## S -> C S/Fc gain: C/Fc gain: Fc/C ## ---------------- ------------------------- ------------------------ ## High Pass zero: Fc C/x pole: Fc C/x ## S -> C Fc/S pole: 0 zero: 0 ## gain: -x gain: -1/x ## ---------------- ------------------------- ------------------------ ## Band Pass zero: b ± sqrt(b^2-FhFl) pole: b ± sqrt(b^2-FhFl) ## S^2+FhFl pole: 0 zero: 0 ## S -> C -------- gain: C/(Fh-Fl) gain: (Fh-Fl)/C ## S(Fh-Fl) b=x/C (Fh-Fl)/2 b=x/C (Fh-Fl)/2 ## ---------------- ------------------------- ------------------------ ## Band Stop zero: b ± sqrt(b^2-FhFl) pole: b ± sqrt(b^2-FhFl) ## S(Fh-Fl) pole: ±sqrt(-FhFl) zero: ±sqrt(-FhFl) ## S -> C -------- gain: -x gain: -1/x ## S^2+FhFl b=C/x (Fh-Fl)/2 b=C/x (Fh-Fl)/2 ## ---------------- ------------------------- ------------------------ ## Bilinear zero: (2+xT)/(2-xT) pole: (2+xT)/(2-xT) ## 2 z-1 pole: -1 zero: -1 ## S -> - --- gain: (2-xT)/T gain: (2-xT)/T ## T z+1 ## ---------------- ------------------------- ------------------------ ## ## where C is the cutoff frequency of the initial lowpass filter, Fc is ## the edge of the target low/high pass filter and [Fl,Fh] are the edges ## of the target band pass/stop filter. With abundant tedious algebra, ## you can derive the above formulae yourself by substituting the ## transform for S into H(S)=S-x for a zero at x or H(S)=1/(S-x) for a ## pole at x, and converting the result into the form: ## ## H(S)=g prod(S-Xi)/prod(S-Xj) ## ## The transforms are from the references. The actual pole-zero-gain ## changes I derived myself. ## ## Please note that a pole and a zero at the same place exactly cancel. ## This is significant for High Pass, Band Pass and Band Stop filters ## which create numerous extra poles and zeros, most of which cancel. ## Those which do not cancel have a "fill-in" effect, extending the ## shorter of the sets to have the same number of as the longer of the ## sets of poles and zeros (or at least split the difference in the case ## of the band pass filter). There may be other opportunistic ## cancellations but I will not check for them. ## ## Also note that any pole on the unit circle or beyond will result in ## an unstable filter. Because of cancellation, this will only happen ## if the number of poles is smaller than the number of zeros and the ## filter is high pass or band pass. The analytic design methods all ## yield more poles than zeros, so this will not be a problem. ## ## References: ## ## Proakis & Manolakis (1992). Digital Signal Processing. New York: ## Macmillan Publishing Company. function [Sz, Sp, Sg] = sftrans(Sz, Sp, Sg, W, stop) if (nargin != 5) print_usage; end 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"); end 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))]; end end 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))]; end end end 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)]; end end 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; end end endfunction signal/inst/sgolay.m0000644000000000000000000001002412124117010013074 0ustar 00000000000000## 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; if not, see . ## F = sgolay (p, n [, m [, ts]]) ## Computes the filter coefficients for all Savitzsky-Golay smoothing ## filters of order p for length n (odd). m can be used in order to ## get directly the mth derivative. In this case, ts is a scaling factor. ## ## The early rows of F smooth based on future values and later rows ## smooth based on past values, with the middle row using half future ## and half past. In particular, you can use row i to estimate x(k) ## based on the i-1 preceding values and the n-i following values of x ## values as y(k) = F(i,:) * x(k-i+1:k+n-i). ## ## Normally, you would apply the first (n-1)/2 rows to the first k ## points of the vector, the last k rows to the last k points of the ## vector and middle row to the remainder, but for example if you were ## running on a realtime system where you wanted to smooth based on the ## all the data collected up to the current time, with a lag of five ## samples, you could apply just the filter on row n-5 to your window ## of length n each time you added a new sample. ## ## Reference: Numerical recipes in C. p 650 ## ## See also: sgolayfilt ## 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,:); end ## 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/inst/sgolayfilt.m0000644000000000000000000001035012124117010013755 0ustar 00000000000000## 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; if not, see . ## y = sgolayfilt (x, p, n [, m [, ts]]) ## 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. ## ## y = sgolayfilt (x, F) ## Smooth the data in x with smoothing filter F computed by sgolay. ## ## These filters are particularly good at preserving lineshape while ## removing high frequency squiggles. Particularly, compare a 5 sample ## averager, an order 5 butterworth lowpass filter (cutoff 1/3) and ## sgolayfilt(x, 3, 5), the best cubic estimated from 5 points: ## ## [b, a] = butter(5,1/3); ## x=[zeros(1,15), 10*ones(1,10), zeros(1,15)]; ## plot(sgolayfilt(x),"r;sgolayfilt;",... ## filtfilt(ones(1,5)/5,1,x),"g;5 sample average;",... ## filtfilt(b,a,x),"c;order 5 butterworth;",... ## x,"+b;original data;"); ## ## See also: sgolay ## TODO: 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); title("boxcar"); %! axis([1 40 -2 15]); %! 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;"); title(""); %! %! x=x+randn(size(x))/2; %! subplot(122); title("boxcar+noise"); %! 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;"); title(""); %!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); title("sinusoid"); %! axis([0 1 -1.5 2.5]); %! 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;"); title(""); %! %! x=x+0.2*randn(size(x)); % signal+noise %! subplot(122); title("sinusoid+noise"); %! 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;"); title(""); signal/inst/shanwavf.m0000644000000000000000000000231012124117010013412 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{psi,x}] =} shanwavf (@var{lb,ub,n,fb,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/inst/sigmoid_train.m0000644000000000000000000000752712124117010014444 0ustar 00000000000000%% 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; if not, see . %% -*- texinfo -*- %% @deftypefn {Function File} @var{y} = sigmoid_train(@var{t}, @var{ranges}, @var{rc}) %% %% Evaluates 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 sigmod @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 a array that defines the rising and falling time %% constants of each sigmoids. Its size must equal the size of @var{ranges}. %% %% Run @code{demo sigmoid_train} to some examples of the use of this function. %% %% @end deftypefn function envelope = 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]) %% All bumps have different time constant but are symmetric if length(timeconstant) ~= nRanges error('signalError','Length of time constant must equal number of ranges.') end if isrow (timeconstant) timeconstant = timeconstant'; end timeconstant = repmat (timeconstant,1,2); end %% Make sure t is horizontal flag_transposed = false; if iscolumn (t) t = t.'; flag_transposed = true; end [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; % 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.'; end end %!demo %! % Vectorized %! t = linspace (0, 2, 500); %! range = [0.1 0.4; 0.6 0.8; 1 2]; %! rc = [1e-2 1e-2; 1e-3 1e-3; 2e-2 2e-2]; %! y = sigmoid_train (t, range, rc); %! %! close all %! 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'); %! end %! 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 %! % 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); %! %! close all %! 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'); %! end %! 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/inst/sos2tf.m0000644000000000000000000000502012124117010013016 0ustar 00000000000000%% 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; 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{Bscale}) %% 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:@* %% @var{sos} = [@var{B1}.' @var{A1}.'; ...; @var{BN}.' @var{AN}.'], where@* %% @code{@var{B1}.'==[b0 b1 b2] and @var{A1}.'==[1 a1 a2]} for %% section 1, etc.@* %% b0 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{Bscale} 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, Bscale = 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'); end A = 1; B = 1; for i=1:N B = conv(B, sos(i,1:3)); A = conv(A, sos(i,4:6)); end nB = length(B); while nB && B(nB)==0 B=B(1:nB-1); nB=length(B); end nA = length(A); while nA && A(nA)==0 A=A(1:nA-1); nA=length(A); end B = B * Bscale; endfunction %!test %! B=[1 1]; %! A=[1 0.5]; %! [sos,g] = tf2sos(B,A); %! [Bh,Ah] = sos2tf(sos,g); %! assert({Bh,Ah},{B,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({Bh,Ah},{B,A},100*eps); signal/inst/sos2zp.m0000644000000000000000000000602012124117010013037 0ustar 00000000000000%% 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; if not, see . %% -*- texinfo -*- %% @deftypefn {Function File} {[@var{z}, @var{p}, @var{g}] =} sos2zp (@var{sos}) %% @deftypefnx {Function File} {[@var{z}, @var{p}, @var{g}] =} sos2zp (@var{sos}, @var{Bscale}) %% 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:@* %% @var{sos} = [@var{B1}.' @var{A1}.'; ...; @var{BN}.' @var{AN}.'], where@* %% @code{@var{B1}.'==[b0 b1 b2] and @var{A1}.'==[1 a1 a2]} for %% section 1, etc.@* %% b0 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{Bscale} 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{g} = overall gain = @var{B}(Inf) %% @end itemize %% %% EXAMPLE: %% @example %% [z,p,g] = sos2zp([1 0 1, 1 0 -0.81; 1 0 0, 1 0 0.49]) %% => z = [i; -i; 0; 0], p = [0.9, -0.9, 0.7i, -0.7i], g=1 %% @end example %% %% @seealso{zp2sos sos2tf tf2sos zp2tf tf2zp} %% @end deftypefn function [z,p,g] = sos2zp (sos, Bscale = 1) if (nargin < 1 || nargin > 2) print_usage; endif gains = sos(:,1); % All b0 coeffs g = prod(gains)*Bscale; % pole-zero gain if g==0, error('sos2zp: one or more section gains is zero'); end 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'); end 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; end end %!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/inst/specgram.m0000644000000000000000000002127212124117010013406 0ustar 00000000000000## 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; if not, see . ## usage: [S [, f [, t]]] = specgram(x [, n [, Fs [, window [, overlap]]]]) ## ## Generate a spectrogram for the signal. This chops the signal into ## overlapping slices, windows each slice and applies a Fourier ## transform to determine the frequency components at that slice. ## ## x: vector of samples ## n: size of fourier transform window, or [] for default=256 ## Fs: sample rate, or [] for default=2 Hz ## window: shape of the fourier transform window, or [] for default=hanning(n) ## Note: window length can be specified instead, in which case ## window=hanning(length) ## overlap: overlap with previous window, or [] for default=length(window)/2 ## ## Return values ## S is complex output of the FFT, one row per slice ## f is the frequency indices corresponding to the rows of S. ## t is the time indices corresponding to the columns of S. ## If no return value is requested, the spectrogram is displayed instead. ## ## Example ## x = chirp([0:0.001:2],0,2,500); # freq. sweep from 0-500 over 2 sec. ## Fs=1000; # sampled every 0.001 sec so rate is 1 kHz ## step=ceil(20*Fs/1000); # one spectral slice every 20 ms ## window=ceil(100*Fs/1000); # 100 ms data window ## specgram(x, 2^nextpow2(window), Fs, window, window-step); ## ## ## Speech spectrogram ## [x, Fs] = auload(file_in_loadpath("sample.wav")); # audio file ## step = fix(5*Fs/1000); # one spectral slice every 5 ms ## window = fix(40*Fs/1000); # 40 ms data window ## fftn = 2^nextpow2(window); # next highest power of 2 ## [S, f, t] = specgram(x, fftn, Fs, window, window-step); ## S = abs(S(2:fftn*4000/Fs,:)); # magnitude in range 0= minF & f <= maxF); ## ## Then there is the choice of colormap. A brightness varying colormap ## such as copper or bone gives good shape to the ridges and valleys. A ## hue varying colormap such as jet or hsv gives an indication of the ## steepness of the slopes. The final spectrogram is displayed in log ## energy scale and by convention has low frequencies on the bottom of ## the image: ## ## imagesc(t, f, flipud(log(S(idx,:)))); 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; ## make sure x is a vector elseif columns(x) != 1 && rows(x) != 1 error ("specgram data must be a vector"); end if columns(x) != 1, x = x'; end ## if only the window length is given, generate hanning window if length(window) == 1, window = hanning(window); end ## should be extended to accept a vector of frequencies at which to ## evaluate the fourier transform (via filterbank or chirp ## z-transform) if length(n)>1, error("specgram doesn't handle frequency vectors yet"); endif ## compute window offsets win_size = length(window); if (win_size > n) n = win_size; warning ("specgram fft size adjusted to %d", n); end 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; end 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); %! disp("shows a diagonal from bottom left to top right"); %! input("press enter:","s"); %! %! ## test of returned values %! S = specgram(x, 2^nextpow2(window), Fs, window, window-step); %! imagesc(20*log10(flipud(abs(S)))); %! disp("same again, but this time using returned value"); %!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, the square wave is +1 for ## that portion of the time. ## ## @verbatim ## on time ## duty cycle = ------------------ ## on time + off time ## @end verbatim ## ## @seealso{cos, sawtooth, sin, tripuls} ## @end deftypefn function v = square (t, duty = 0.5) if (nargin < 1 || nargin > 2) print_usage; endif t /= 2*pi; v = ones(size(t)); v(t-floor(t) >= duty) = -1; endfunction signal/inst/ss2tf.m0000644000000000000000000000326412124117010012647 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{num}, @var{den}] =} ss2tf (@var{a}, @var{b}, @var{c}, @var{d}) ## Conversion from transfer function to state-space. ## The state space system: ## @iftex ## @tex ## $$ \dot x = Ax + Bu $$ ## $$ y = Cx + Du $$ ## @end tex ## @end iftex ## @ifinfo ## @example ## . ## x = Ax + Bu ## y = Cx + Du ## @end example ## @end ifinfo ## ## is converted to a transfer function: ## @iftex ## @tex ## $$ G(s) = { { \rm num }(s) \over { \rm den }(s) } $$ ## @end tex ## @end iftex ## @ifinfo ## @example ## ## num(s) ## G(s)=------- ## den(s) ## @end example ## @end ifinfo ## ## @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/inst/ss2zp.m0000644000000000000000000000232212124117010012661 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{pol}, @var{zer}, @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/inst/tf2sos.m0000644000000000000000000000414312124117010013023 0ustar 00000000000000%% 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; if not, see . %% -*- texinfo -*- %% @deftypefn {Function File} {[@var{sos}, @var{g}] =} 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: %% @var{sos} = matrix of series second-order sections, one per row:@* %% @var{sos} = [@var{B1}.' @var{A1}.'; ...; @var{BN}.' @var{AN}.'], where@* %% @code{@var{B1}.'==[b0 b1 b2] and @var{A1}.'==[1 a1 a2]} for %% section 1, etc.@* %% b0 must be nonzero for each section (zeros at infinity not supported). %% @var{Bscale} is an overall gain factor that effectively scales %% any one of the @var{B}i vectors. %% %% 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,g] = tf2zp(B(:)',A(:)'); sos = zp2sos(z,p,g); 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/inst/tf2ss.m0000644000000000000000000000350412124117010012644 0ustar 00000000000000## 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; 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: ## @iftex ## @tex ## $$ \dot x = Ax + Bu $$ ## $$ y = Cx + Du $$ ## @end tex ## @end iftex ## @ifinfo ## @example ## . ## x = Ax + Bu ## y = Cx + Du ## @end example ## @end ifinfo ## is obtained from a transfer function: ## @iftex ## @tex ## $$ G(s) = { { \rm num }(s) \over { \rm den }(s) } $$ ## @end tex ## @end iftex ## @ifinfo ## @example ## num(s) ## G(s)=------- ## den(s) ## @end example ## @end ifinfo ## ## 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/inst/tf2zp.m0000644000000000000000000000247212124117010012653 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{zer}, @var{pol}, @var{k}] =} tf2zp (@var{num}, @var{den}) ## Converts 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/inst/tfe.m0000644000000000000000000000366012124117010012364 0ustar 00000000000000%% 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; 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.' ); end 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} = []; end end 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; end pwelch(saved_compatib); end signal/inst/tfestimate.m0000644000000000000000000000335412124117010013753 0ustar 00000000000000%% 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; if not, see . %% Usage: %% [Pxx,freq]=tfestimate(x,y,window,overlap,Nfft,Fs,range) %% %% Estimate transfer function of system with input "x" and output "y". %% Use the Welch (1967) periodogram/FFT method. %% See "help pwelch" for description of arguments, hints and references. function [varargout] = tfestimate(varargin) %% %% Check fixed argument if (nargin < 2 || nargin > 7) print_usage (); end 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} = []; end end 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; end end signal/inst/triang.m0000644000000000000000000000434212124117010013070 0ustar 00000000000000## 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; if not, see . ## usage: w = triang (L) ## ## Returns the filter coefficients of a triangular window of length L. ## Unlike the bartlett window, triang does not go to zero at the edges ## of the window. For odd L, triang(L) is equal to bartlett(L+2) except ## for the zeros at the edges of the window. function w = triang(L) if (nargin != 1) print_usage; elseif (!isscalar(L) || L != fix (L) || L < 1) error("triang: L has to be an integer > 0"); endif w = 1 - abs ([-(L-1):2:(L-1)]' / (L+rem(L,2))); endfunction %!error triang %!error triang(1,2) %!error triang([1,2]); %!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)); %!demo %! subplot(221); axis([-1, 1, 0, 1.3]); grid("on"); %! title("comparison with continuous for odd n"); %! 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;"); %! %! subplot(222); axis([-1, 1, 0, 1.3]); grid("on"); %! n=8; k=(n-1)/2; t=[-k:0.1:k]/(k+1/2); %! title("note the higher peak for even n"); %! plot(t,1+1/n-abs(t),";continuous;",[-k:k]/(k+1/2),triang(n),"g*;discrete;"); %! %! subplot(223); axis; grid("off"); %! title("n odd, triang(n)==bartlett(n+2)"); %! n=7; %! plot(0:n+1,bartlett(n+2),"g-*;bartlett;",triang(n),"r-+;triang;"); %! %! subplot(224); axis; grid("off"); %! title("n even, triang(n)!=bartlett(n+2)"); %! n=8; %! plot(0:n+1,bartlett(n+2),"g-*;bartlett;",triang(n),"r-+;triang;"); %! %! subplot(111); title(""); signal/inst/tripuls.m0000644000000000000000000000472112124117010013307 0ustar 00000000000000## 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; if not, see . ## usage: y = tripuls(t, w, skew) ## ## Generate a triangular pulse over the interval [-w/2,w/2), sampled at ## times t. This is useful with the function pulstran for generating a ## series pulses. ## ## skew is a value between -1 and 1, indicating the relative placement ## of the peak within the width. -1 indicates that the peak should be ## at -w/2, and 1 indicates that the peak should be at w/2. ## ## Example ## fs = 11025; # arbitrary sample rate ## f0 = 100; # pulse train sample rate ## w = 0.3/f0; # pulse width 3/10th the distance between pulses ## auplot(pulstran(0:1/fs:4/f0, 0:1/f0:4/f0, 'tripuls', w), fs); ## ## See also: pulstran function y = tripuls (t, w = 1, skew = 0) if nargin<1 || nargin>3, print_usage; endif y = zeros(size(t)); peak = skew*w/2; try wfi = warning("off", "Octave:fortran-indexing"); catch wfi = 0; end unwind_protect 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 unwind_protect_cleanup warning(wfi); end_unwind_protect endfunction %!assert(tripuls(0:1/100:0.3,.1), tripuls([0:1/100:0.3]',.1)'); %!assert(isempty(tripuls([],.1))); %!demo %! fs = 11025; # arbitrary sample rate %! f0 = 100; # pulse train sample rate %! w = 0.5/f0; # pulse width 1/10th the distance between pulses %! subplot(211); ylabel("amplitude"); xlabel("time (ms)"); %! title("graph shows 5 ms pulses at 0,10,20,30 and 40 ms"); %! auplot(pulstran(0:1/fs:4/f0, 0:1/f0:4/f0, 'tripuls', w), fs); %! subplot(212); %! title("graph shows 5 ms pulses at 0,10,20,30 and 40 ms, skew -0.5"); %! auplot(pulstran(0:1/fs:4/f0, 0:1/f0:4/f0, 'tripuls', w, -0.5), fs); %! title(""); xlabel(""); ylabel(""); signal/inst/tukeywin.m0000644000000000000000000000415612124117010013466 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {@var{w} =} tukeywin (@var{L}, @var{r}) ## Return the filter coefficients of a Tukey window (also known as the ## cosine-tapered window) of length @var{L}. @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} ## egals 0 and a full box for @var{r} egals 1. By default @var{r} is set ## to 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. ## @end deftypefn function w = tukeywin (L, r = 1/2) if (nargin < 1 || nargin > 2) print_usage; 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 (L, 1); case 1, ## Hanning window w = hanning (L); otherwise ## cosine-tapered window t = linspace(0,1,L)(1:end/2)'; w = (1 + cos(pi*(2*t/r-1)))/2; w(floor(r*(L-1)/2)+2:end) = 1; w = [w; ones(mod(L,2)); flipud(w)]; endswitch endfunction %!demo %! L = 100; %! r = 1/3; %! w = tukeywin (L, r); %! title(sprintf("%d-point Tukey window, R = %d/%d", L, [p, q] = rat(r), q)); %! plot(w); signal/inst/upsample.m0000644000000000000000000000237412124117010013435 0ustar 00000000000000## 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 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 n zeros. ## @seealso{decimate, downsample, interp, resample, upfirdn} ## @end deftypefn function y = upsample (x, n, phase = 0) if nargin<2 || nargin>3, print_usage; end if phase > n - 1 warning("This is incompatible with Matlab (phase = 0:n-1). See ... octave-forge signal package release notes for details." ) end [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.'; end else y = zeros(n*nr,nc); y(phase + 1:n:end,:) = x; end end %!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/inst/welchwin.m0000644000000000000000000000650012124117010013422 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{w}] =} welchwin(@var{L},@var{c}) ## Returns a row vector containing a Welch window, given by ## @var{w}(n)=1-(n/N-1)^2, n=[0,1, ... @var{L}-1]. ## Argument @var{L} is the length of the window. ## Optional argument @var{c} specifies a "symmetric" window (the default), ## or a "periodic" window. ## ## A symmetric window has zero at each end and maximum in the middle; ## @var{L} must be an integer larger than 2. ## @code{if c=="symmetric", N=(L-1)/2} ## ## A periodic window wraps around the cyclic interval [0,1, ... @var{L}-1], ## and is intended for use with the DFT (functions fft(), ## periodogram() etc). ## @var{L} must be an integer larger than 1. ## @code{if c=="periodic", N=@var{L}/2}. ## ## @seealso{blackman, kaiser} ## @end deftypefn function [w] = welchwin(L,c) if (nargin < 1 || nargin>2 ) print_usage; endif symmetric=1; if ( nargin==2 && ! isempty(c) ) if ( ! ischar(c) || size(c,1) != 1 || ( ! strcmp(c,'periodic') && ! strcmp(c,'symmetric') ) ) error( "arg 2 (c) must be \"periodic\" or \"symmetric\"" ) endif symmetric = ! strcmp(c,'periodic'); endif ## ## Periodic window is not properly defined if L<2. ## Symmetric window is not properly defined if L<3. min_L = 2 + symmetric; if ( ! isreal(L) || ! isscalar(L) || L. ## -*- texinfo -*- ## @deftypefn {Function File} {@var{w} =} window (@var{f}, @var{n}, @var{opts}) ## Create a @var{n}-point windowing 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, n, varargin) if (nargin == 0) error ("window: UI tool not supported"); elseif (nargin > 1) w = feval (f, n, varargin{:}); if (nargout > 0) wout = w; endif else print_usage (); endif endfunction signal/inst/wkeep.m0000644000000000000000000000340112124117010012712 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{y}] =} wkeep(@var{x,l,opt}) ## Extract the elements of x of size 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; end if(isvector(x)) if(l > length(x)) error('l must be or equal the size of x'); end 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'); end 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'); end 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'); end y=x(firstr:firstr+l(1)-1,firstc:firstc+l(2)-1); end end end signal/inst/wrev.m0000644000000000000000000000206712124117010012571 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{y}] =} wrev(@var{x}) ## Reverse the order of the element of the vector x. ## @seealso{flipud, fliplr} ## @end deftypefn function y = wrev(x) if (nargin < 1|| nargin > 1); print_usage; end if(~isvector(x)) error('x must be a vector'); end l = length(x); k = 0:l-1; y = x(l-k); endfunction signal/inst/xcorr.m0000644000000000000000000002565712124117010012755 0ustar 00000000000000## 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; 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 ## ## @iftex ## @tex ## $$ R_{xy}(k) = \sum_{i=1}^{N} x_{i+k} \conj(y_i), ## @end tex ## @end iftex ## @ifnottex ## @example ## N ## R_xy(k) = sum x_@{i+k@} conj(y_i), ## i=1 ## @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 unbiassed 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 colummn 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 uncessary 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/inst/xcorr2.m0000644000000000000000000001127112124117010013022 0ustar 00000000000000## 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; 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 negavtive 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/inst/xcov.m0000644000000000000000000000465412124117010012571 0ustar 00000000000000## 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; 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 ## XXX FIXME XXX --- 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/inst/zerocrossing.m0000644000000000000000000000430712124117010014334 0ustar 00000000000000## 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; 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/inst/zp2sos.m0000644000000000000000000000742512124117010013051 0ustar 00000000000000%% 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; if not, see . %% -*- texinfo -*- %% @deftypefn {Function File} {[@var{sos}, @var{g}] =} zp2sos (@var{z}, @var{p}) %% @deftypefnx {Function File} {[@var{sos}, @var{g}] =} zp2sos (@var{z}, @var{p}, @var{g}) %% 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{g} = 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:@* %% @var{sos} = [@var{B1}.' @var{A1}.'; ...; @var{BN}.' @var{AN}.'], where@* %% @code{@var{B1}.'==[b0 b1 b2] and @var{A1}.'==[1 a1 a2]} for %% section 1, etc.@* %% b0 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{Bscale} is an overall gain factor that effectively scales %% any one of the @var{B}i vectors. %% @end itemize %% %% EXAMPLE: %% @example %% [z,p,g] = tf2zp([1 0 0 0 0 1],[1 0 0 0 0 .9]); %% [sos,g] = zp2sos(z,p,g) %% %% 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,g) if nargin<3, g=1; end if nargin<2, p=[]; end [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; end 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; end % Pair up real poles: if npr if mod(npr,2)==1, pr=[pr;0]; npr=npr+1; end 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; end 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)]; end 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)]; end end end %!test %! B=[1 0 0 0 0 1]; A=[1 0 0 0 0 .9]; %! [z,p,g] = tf2zp(B,A); %! [sos,g] = zp2sos(z,p,g); %! [Bh,Ah] = sos2tf(sos,g); %! assert({Bh,Ah},{B,A},100*eps); signal/inst/zp2ss.m0000644000000000000000000000350312124117010012663 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{a}, @var{b}, @var{c}, @var{d}] =} zp2ss (@var{zer}, @var{pol}, @var{k}) ## Conversion from zero / pole to state space. ## ## @strong{Inputs} ## @table @var ## @item zer ## @itemx pol ## 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{zer} means that @math{x-jy} is also in @var{zer}). ## @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: ## @iftex ## @tex ## $$ \dot x = Ax + Bu $$ ## $$ y = Cx + Du $$ ## @end tex ## @end iftex ## @ifinfo ## @example ## . ## x = Ax + Bu ## y = Cx + Du ## @end example ## @end ifinfo ## @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/inst/zp2tf.m0000644000000000000000000000270412124117010012651 0ustar 00000000000000## 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; if not, see . ## -*- texinfo -*- ## @deftypefn {Function File} {[@var{num}, @var{den}] =} zp2tf (@var{zer}, @var{pol}, @var{k}) ## Converts zeros / poles to a transfer function. ## ## @strong{Inputs} ## @table @var ## @item zer ## @itemx pol ## 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/inst/zplane.m0000644000000000000000000001210112124117010013065 0ustar 00000000000000## Copyright (C) 1999, 2001 Paul Kienzle ## Copyright (C) 2004 Stefan van der Walt ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See 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 . ## usage: zplane(b [, a]) or zplane(z [, p]) ## ## Plot the poles and zeros. If the arguments are row vectors then they ## represent filter coefficients (numerator polynomial b and denominator ## polynomial a), but if they are column vectors or matrices then they ## represent poles and zeros. ## ## This is a horrid interface, but I didn't choose it; better would be ## to accept b,a or z,p,g like other functions. The saving grace is ## that poly(x) always returns a row vector and roots(x) always returns ## a column vector, so it is usually right. You must only be careful ## when you are creating filters by hand. ## ## Note that due to the nature of the roots() function, poles and zeros ## may be displayed as occurring around a circle rather than at a single ## point. ## ## The transfer function is ## ## B(z) b0 + b1 z^(-1) + b2 z^(-2) + ... + bM z^(-M) ## H(z) = ---- = -------------------------------------------- ## A(z) a0 + a1 z^(-1) + a2 z^(-2) + ... + aN z^(-N) ## ## b0 (z - z1) (z - z2) ... (z - zM) ## = -- z^(-M+N) ------------------------------ ## a0 (z - p1) (z - p2) ... (z - pN) ## ## The denominator a defaults to 1, and the poles p defaults to []. ## TODO: Consider a plot-like interface: ## TODO: zplane(x1,y1,fmt1,x2,y2,fmt2,...) ## TODO: with y_i or fmt_i optional as usual. This would allow ## TODO: legends and control over point colour and filters of ## TODO: different orders. function zplane(z, p = []) if (nargin < 1 || nargin > 2) print_usage; end 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; text(); plot_with_labels(z, "o"); plot_with_labels(p, "x"); refresh; r = exp(2i*pi*[0:100]/100); plot(real(r), imag(r),'k'); hold on; axis equal; grid on; axis(1.05*[xmin, xmax, ymin, ymax]); if (!isempty(p)) h = plot(real(p), imag(p), "bx"); set (h, 'MarkerSize', 7); endif if (!isempty(z)) h = plot(real(z), imag(z), "bo"); set (h, 'MarkerSize', 7); endif hold off; endfunction function plot_with_labels(x, symbol) if ( !isempty(x) ) x_u = unique(x(:)); for i = 1:length(x_u) n = sum(x_u(i) == x(:)); if (n > 1) text(real(x_u(i)), imag(x_u(i)), [" " num2str(n)]); endif endfor col = "rgbcmy"; for c = 1:columns(x) plot(real( x(:,c) ), imag( x(:,c) ), [col(mod(c,6)),symbol ";;"]); 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 plane"); %! subplot(231); title("transfer function form"); zplane(sys_b, sys_a); %! subplot(232); title("pole-zero form"); zplane(z,p); %! subplot(233); title("empty p"); zplane(z); %! subplot(234); title("empty a"); zplane(sys_b); %! disp("The matrix plot has 2 sets of points, one inside the other"); %! subplot(235); title("matrix"); zplane([z, 0.7*z], [p, 0.7*p]); signal/src/Makefile0000644000000000000000000000055312124117010012700 0ustar 00000000000000MKOCTFILE ?= mkoctfile all: __fwht__.oct cl2bp.oct remez.oct medfilt1.oct sosfilt.oct upfirdn.oct %.oct: %.cc $(MKOCTFILE) -Wall -s $< cl2bp.o: cl2bp.cc cl2bp_lib.h $(MKOCTFILE) -Wall -c $< cl2bp_lib.o: cl2bp_lib.cc cl2bp_lib.h $(MKOCTFILE) -Wall -c $< cl2bp.oct: cl2bp.o cl2bp_lib.o $(MKOCTFILE) -Wall -s $^ clean: rm -f *.o octave-core core *.oct *~ signal/src/__fwht__.cc0000644000000000000000000000323612124117010013314 0ustar 00000000000000// Copyright (C) 2013 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; 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\n") { 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 (); } signal/src/cl2bp.cc0000644000000000000000000001116512124117010012552 0ustar 00000000000000// 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; if not, see . #include #include "cl2bp_lib.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}\ [, @var{gridsize}])\n\ \n\ Constrained L2 bandpass FIR filter design. This is a fast implementation of the algorithm\n\ cited below. Compared to @dfn{remez}, it offers implicit specification of transition bands,\n\ a higher likelihood of convergence, and an error criterion combining features of both L2 and\n\ Chebyshev approaches.@*\n\ Inputs:@*\n\ @var{m}: degree of cosine polynomial, i.e. the number of output coefficients will be @var{m}*2+1@*\n\ @var{w1}, @var{w2}: bandpass filter cutoffs in the range 0 <= @var{w1} < @var{w2} <= pi,\n\ where pi is the Nyquist frequency@*\n\ @var{up}: vector of 3 upper bounds for [stopband1, passband, stopband2]@*\n\ @var{lo}: vector of 3 lower bounds for [stopband1, passband, stopband2]@*\n\ @var{gridsize}: search grid size; larger values may improve accuracy,\n\ but greatly increase calculation time.@*\n\ Output:@*\n\ A vector of @var{m}*2+1 FIR coefficients, or an empty value if the solver failed to converge.@*\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\ Original Paper: I. W. Selesnick, M. Lang, and C. S. Burrus. A modified algorithm for\n\ constrained least square design of multiband FIR filters without 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) { gripe_wrong_type_arg("cl2bp", args (0)); return retval; } const double w1 = args(1).double_value(); if (error_state) { gripe_wrong_type_arg("cl2bp", args (1)); return retval; } const double w2 = args(2).double_value(); if (error_state) { gripe_wrong_type_arg("cl2bp", args (2)); return retval; } const ColumnVector up_vector(args(3).vector_value()); if (error_state) { gripe_wrong_type_arg("cl2bp", args (3)); return retval; } const ColumnVector lo_vector(args(4).vector_value()); if (error_state) { gripe_wrong_type_arg("cl2bp", args (4)); return retval; } if (up_vector.length() != 3 || lo_vector.length() != 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) { gripe_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(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; 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]); 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); } 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/src/cl2bp_lib.h0000644000000000000000000000733312124117010013244 0ustar 00000000000000// 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; 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& src) { } // 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/src/medfilt1.cc0000644000000000000000000001542612124117010013261 0ustar 00000000000000/* * Copyright 2000 Paul Kienzle * This source code is freely redistributable and may be used for * any purpose. This copyright notice must be maintained. * Paul Kienzle is not responsible for the consequences of using * this software. * * Mar 2000 - Kai Habel (kahacjde@linux.zrz.tu-berlin.de) * Change: ColumnVector x=arg(i).vector_value(); * to: ColumnVector x=ColumnVector(arg(i).vector_value()); * Oct 2000 - Paul Kienzle (pkienzle@users.sf.net) * rewrite to ignore NaNs rather than replacing them with zero * extend to handle matrix arguments */ #include #include #include #include using namespace std; // The median class holds a sorted data window. This window is // intended to slide over the data, so when the window shifts // by one position, the old value from the start of the window must // be removed and the new value from the end of the window must // be added. Since removals and additions generally occur in pairs, // a hole is left in the sorted window when the value is removed so // that on average, fewer values need to be shifted to close the // hole and open a new one in the sorted position. class Median { private: double *window; // window data int max; // length of window used int hole; // position of hole, or max if no hole void close_hole() // close existing hole { // move hole to the end of the window while (hole < max-1) { window[hole] = window[hole+1]; hole++; } // shorten window (if no hole, then hole==max) if (hole == max-1) max--; } void print(); public: Median(int n) { max=hole=0; window = new double[n]; } ~Median(void) { delete [] window; } void add(double v); // add a new value void remove(double v); // remove an existing value void clear() { max=hole=0; } // clear the window double operator() (); // find the median in the window } ; // Print the sorted window, and indicate any hole void Median::print() { octave_stdout << "[ "; for (int i=0; i < max; i++) { if (i == hole) octave_stdout << "x "; else octave_stdout << window[i] << " "; } octave_stdout << " ]"; } // Remove a value from the sorted window, leaving a hole. The caller // must promise to only remove values that they have added. void Median::remove(double v) { // NaN's are not added or removed if (lo_ieee_isnan(v)) return; // octave_stdout << "Remove " << v << " from "; print(); // only one hole allowed, so close pre-existing ones close_hole(); // binary search to find the value to remove int lo = 0, hi=max-1; hole = hi/2; while (lo <= hi) { if (v > window[hole]) lo = hole+1; else if (v < window[hole]) hi = hole-1; else break; hole = (lo+hi)/2; } // Verify that it is the correct value to replace // Note that we shouldn't need this code since we are always replacing // a value that is already in the window, but for some reason // v==window[hole] occasionally doens't work. if (v != window[hole]) { for (hole = 0; hole < max-1; hole++) if (fabs(v-window[hole]) < fabs(v-window[hole+1])) break; warning ("medfilt1: value %f not found---removing %f instead", v, window[hole]); print(); octave_stdout << endl; } // octave_stdout << " gives "; print(); octave_stdout << endl; } // Insert a new value in the sorted window, plugging any holes, or // extending the window as necessary. The caller must promise not // to add more values than median was created with, without // removing some beforehand. void Median::add(double v) { // NaN's are not added or removed if (lo_ieee_isnan(v)) return; // octave_stdout << "Add " << v << " to "; print(); // If no holes, extend the array if (hole == max) max++; // shift the hole up to the beginning as far as it can go. while (hole > 0 && window[hole-1] > v) { window[hole] = window[hole-1]; hole--; } // or shift the hole down to the end as far as it can go. while (hole < max-1 && window[hole+1] < v) { window[hole] = window[hole+1]; hole++; } // plug in the replacement value window[hole] = v; // close the hole hole = max; // octave_stdout << " gives "; print(); octave_stdout << endl; } // Compute the median value from the sorted window // Return the central value if there is one or the average of the // two central values. Return NaN if there are no values. double Median::operator()() { close_hole(); if (max % 2 == 1) return window[(max-1)/2]; else if (max == 0) return lo_ieee_nan_value(); else return (window[max/2-1]+window[max/2])/2.0; } DEFUN_DLD (medfilt1, args, , "y = medfilt1(x [, n])\n\ \n\ Apply a median filter of length n to the signal x. A sliding window is\n\ applied to the data, and for each step the median value in the window is\n\ returned. If n is odd then the window for y(i) is x(i-(n-1)/2:i+(n-1)/2).\n\ If n is even then the window is x(i-n/2:i+n/2-1) and the two values in the\n\ center of the sorted window are averaged. If n is not given, then 3 is used.\n\ NaNs are ignored, as are values beyond the ends, by taking the median of\n\ the remaining values.") { octave_value_list retval; int nargin = args.length(); if (nargin < 1 || nargin > 3) { print_usage (); return retval; } if (args(0).is_complex_type()) { error("medfilt1 cannot process complex vectors"); return retval; } int n=3; // length of the filter (default 3) if (nargin > 1) n = NINT(args(1).double_value()); if (n < 1) { error ("medfilt1 filter length must be at least 1"); return retval; } // Create a window to hold the sorted median values Median median(n); int mid = n/2; // mid-point of the window Matrix signal(args(0).matrix_value()); int nr = signal.rows(); // number of points to process int nc = signal.columns(); // number of points to process Matrix filter(nr,nc); // filtered signal to return if (nr == 1) // row vector { int start = -n, end = 0, pos=-(n-mid)+1; while (pos < nc) { if (start >= 0) median.remove(signal(0,start)); if (end < nc) median.add(signal(0,end)); if (pos >= 0) filter(0,pos) = median(); start++, end++, pos++; } } else // column vector or matrix { for (int column=0; column < nc; column++) { median.clear(); int start = -n, end = 0, pos=-(n-mid)+1; while (pos < nr) { if (start >= 0) median.remove(signal(start,column)); if (end < nr) median.add(signal(end,column)); if (pos >= 0) filter(pos,column) = median(); start++, end++, pos++; } } } retval(0) = filter; return retval; } /* %!assert(medfilt1([1, 2, 3, 4, 5], 3), [1.5, 2, 3, 4, 4.5]); */ signal/src/remez.cc0000644000000000000000000005606012124117010012675 0ustar 00000000000000// 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; 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 #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 */ 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 reponse 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 = NINT (args(0).double_value()) + 1; // #coeff = filter order+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.length()/2; OCTAVE_LOCAL_BUFFER(double, bands, numbands*2); if (numbands < 1 || o_bands.length()%2 == 1) { error("remez: must have an even number of band edges"); return retval; } for (i=1; i < o_bands.length(); 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.length() != o_bands.length()) { 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.length() != 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 = 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 = 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/src/sosfilt.cc0000644000000000000000000000551712124117010013237 0ustar 00000000000000// 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; if not, see . #include #include #include #include #include #include #include #include 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}.@*\n\ The second order section filter is described by the matrix @var{sos} with:@*\n\ @multitable {col 1} {this is column two}\n\ @item @tab [ @var{B1} @var{A1} ]@*\n\ @item @var{sos} = @tab [ ... ],@*\n\ @item @tab [ @var{BN} @var{AN} ]@*\n\ @end multitable\n\ where @code{@var{B1}=[b0 b1 b2]} and @code{@var{A1}=[1 a1 a2]} for section 1, etc.@*\n\ b0 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) { gripe_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) { gripe_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; if not, see . #include #include #include #include #include #include #include #include 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.length (); 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) { gripe_wrong_type_arg ("upfirdn", args (1)); return retval; } octave_idx_type p = args (2).idx_type_value (); if (error_state) { gripe_wrong_type_arg ("upfirdn", args (2)); return retval; } octave_idx_type q = args (3).idx_type_value (); if (error_state) { gripe_wrong_type_arg ("upfirdn", args (3)); return retval; } // Do the dispatching if (args (0).is_real_matrix ()) { Matrix x = args (0).matrix_value (); if (error_state) { gripe_wrong_type_arg ("upfirdn", args (0)); return retval; } Matrix y = upfirdn (x, h, p, q); retval (0) = y; } else if (args (0).is_complex_matrix ()) { ComplexMatrix x = args (0).complex_matrix_value (); if (error_state) { gripe_wrong_type_arg ("upfirdn", args (0)); return retval; } ComplexMatrix y = upfirdn (x, h, p, q); retval (0) = y; } return retval; }