├── .gitignore
├── LICENSE
├── MANIFEST
├── README.rst
├── docs
├── Makefile
├── make.bat
└── source
│ ├── conf.py
│ └── index.rst
├── english.wav
├── example.py
├── python_speech_features
├── __init__.py
├── base.py
└── sigproc.py
├── requirements.txt
├── setup.py
└── test
└── test_sigproc.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.wav
2 | *.py[cod]
3 |
4 | # C extensions
5 | *.so
6 |
7 | # Packages
8 | *.egg
9 | *.egg-info
10 | dist
11 | build
12 | eggs
13 | parts
14 | bin
15 | var
16 | sdist
17 | develop-eggs
18 | .installed.cfg
19 | lib
20 | lib64
21 | __pycache__
22 |
23 | # Installer logs
24 | pip-log.txt
25 |
26 | # Unit test / coverage reports
27 | .coverage
28 | .tox
29 | nosetests.xml
30 |
31 | # Translations
32 | *.mo
33 |
34 | # Mr Developer
35 | .mr.developer.cfg
36 | .project
37 | .pydevproject
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 James Lyons
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/MANIFEST:
--------------------------------------------------------------------------------
1 | # file GENERATED by distutils, do NOT edit
2 | setup.py
3 | python_speech_features\__init__.py
4 | python_speech_features\base.py
5 | python_speech_features\sigproc.py
6 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | ======================
2 | python_speech_features
3 | ======================
4 |
5 | This library provides common speech features for ASR including MFCCs and filterbank energies.
6 | If you are not sure what MFCCs are, and would like to know more have a look at this
7 | `MFCC tutorial `_
8 |
9 | `Project Documentation `_
10 |
11 | To cite, please use: James Lyons et al. (2020, January 14). jameslyons/python_speech_features: release v0.6.1 (Version 0.6.1). Zenodo. http://doi.org/10.5281/zenodo.3607820
12 |
13 | Installation
14 | ============
15 |
16 | This `project is on pypi `_
17 |
18 | To install from pypi::
19 |
20 | pip install python_speech_features
21 |
22 |
23 | From this repository::
24 |
25 | git clone https://github.com/jameslyons/python_speech_features
26 | python setup.py develop
27 |
28 |
29 | Usage
30 | =====
31 |
32 | Supported features:
33 |
34 | - Mel Frequency Cepstral Coefficients
35 | - Filterbank Energies
36 | - Log Filterbank Energies
37 | - Spectral Subband Centroids
38 |
39 | `Example use `_
40 |
41 | From here you can write the features to a file etc.
42 |
43 |
44 | MFCC Features
45 | =============
46 |
47 | The default parameters should work fairly well for most cases,
48 | if you want to change the MFCC parameters, the following parameters are supported::
49 |
50 | python
51 | def mfcc(signal,samplerate=16000,winlen=0.025,winstep=0.01,numcep=13,
52 | nfilt=26,nfft=512,lowfreq=0,highfreq=None,preemph=0.97,
53 | ceplifter=22,appendEnergy=True)
54 |
55 | ============= ===========
56 | Parameter Description
57 | ============= ===========
58 | signal the audio signal from which to compute features. Should be an N*1 array
59 | samplerate the samplerate of the signal we are working with.
60 | winlen the length of the analysis window in seconds. Default is 0.025s (25 milliseconds)
61 | winstep the step between successive windows in seconds. Default is 0.01s (10 milliseconds)
62 | numcep the number of cepstrum to return, default 13
63 | nfilt the number of filters in the filterbank, default 26.
64 | nfft the FFT size. Default is 512
65 | lowfreq lowest band edge of mel filters. In Hz, default is 0
66 | highfreq highest band edge of mel filters. In Hz, default is samplerate/2
67 | preemph apply preemphasis filter with preemph as coefficient. 0 is no filter. Default is 0.97
68 | ceplifter apply a lifter to final cepstral coefficients. 0 is no lifter. Default is 22
69 | appendEnergy if this is true, the zeroth cepstral coefficient is replaced with the log of the total frame energy.
70 | returns A numpy array of size (NUMFRAMES by numcep) containing features. Each row holds 1 feature vector.
71 | ============= ===========
72 |
73 |
74 | Filterbank Features
75 | ===================
76 |
77 | These filters are raw filterbank energies.
78 | For most applications you will want the logarithm of these features.
79 | The default parameters should work fairly well for most cases.
80 | If you want to change the fbank parameters, the following parameters are supported::
81 |
82 | python
83 | def fbank(signal,samplerate=16000,winlen=0.025,winstep=0.01,
84 | nfilt=26,nfft=512,lowfreq=0,highfreq=None,preemph=0.97)
85 |
86 | ============= ===========
87 | Parameter Description
88 | ============= ===========
89 | signal the audio signal from which to compute features. Should be an N*1 array
90 | samplerate the samplerate of the signal we are working with
91 | winlen the length of the analysis window in seconds. Default is 0.025s (25 milliseconds)
92 | winstep the step between successive windows in seconds. Default is 0.01s (10 milliseconds)
93 | nfilt the number of filters in the filterbank, default 26.
94 | nfft the FFT size. Default is 512.
95 | lowfreq lowest band edge of mel filters. In Hz, default is 0
96 | highfreq highest band edge of mel filters. In Hz, default is samplerate/2
97 | preemph apply preemphasis filter with preemph as coefficient. 0 is no filter. Default is 0.97
98 | returns A numpy array of size (NUMFRAMES by nfilt) containing features. Each row holds 1 feature vector. The second return value is the energy in each frame (total energy, unwindowed)
99 | ============= ===========
100 |
101 |
102 | Reference
103 | =========
104 | sample english.wav obtained from::
105 |
106 | wget http://voyager.jpl.nasa.gov/spacecraft/audio/english.au
107 | sox english.au -e signed-integer english.wav
108 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = build
9 |
10 | # Internal variables.
11 | PAPEROPT_a4 = -D latex_paper_size=a4
12 | PAPEROPT_letter = -D latex_paper_size=letter
13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
14 |
15 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
16 |
17 | help:
18 | @echo "Please use \`make ' where is one of"
19 | @echo " html to make standalone HTML files"
20 | @echo " dirhtml to make HTML files named index.html in directories"
21 | @echo " pickle to make pickle files"
22 | @echo " json to make JSON files"
23 | @echo " htmlhelp to make HTML files and a HTML help project"
24 | @echo " qthelp to make HTML files and a qthelp project"
25 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
26 | @echo " changes to make an overview of all changed/added/deprecated items"
27 | @echo " linkcheck to check all external links for integrity"
28 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
29 |
30 | clean:
31 | -rm -rf $(BUILDDIR)/*
32 |
33 | html:
34 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
35 | @echo
36 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
37 |
38 | dirhtml:
39 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
40 | @echo
41 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
42 |
43 | pickle:
44 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
45 | @echo
46 | @echo "Build finished; now you can process the pickle files."
47 |
48 | json:
49 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
50 | @echo
51 | @echo "Build finished; now you can process the JSON files."
52 |
53 | htmlhelp:
54 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
55 | @echo
56 | @echo "Build finished; now you can run HTML Help Workshop with the" \
57 | ".hhp project file in $(BUILDDIR)/htmlhelp."
58 |
59 | qthelp:
60 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
61 | @echo
62 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
63 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
64 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python_speech_features.qhcp"
65 | @echo "To view the help file:"
66 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python_speech_features.qhc"
67 |
68 | latex:
69 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
70 | @echo
71 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
72 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
73 | "run these through (pdf)latex."
74 |
75 | changes:
76 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
77 | @echo
78 | @echo "The overview file is in $(BUILDDIR)/changes."
79 |
80 | linkcheck:
81 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
82 | @echo
83 | @echo "Link check complete; look for any errors in the above output " \
84 | "or in $(BUILDDIR)/linkcheck/output.txt."
85 |
86 | doctest:
87 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
88 | @echo "Testing of doctests in the sources finished, look at the " \
89 | "results in $(BUILDDIR)/doctest/output.txt."
90 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | REM Command file for Sphinx documentation
4 |
5 | set SPHINXBUILD=sphinx-build
6 | set BUILDDIR=build
7 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
8 | if NOT "%PAPER%" == "" (
9 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
10 | )
11 |
12 | if "%1" == "" goto help
13 |
14 | if "%1" == "help" (
15 | :help
16 | echo.Please use `make ^` where ^ is one of
17 | echo. html to make standalone HTML files
18 | echo. dirhtml to make HTML files named index.html in directories
19 | echo. pickle to make pickle files
20 | echo. json to make JSON files
21 | echo. htmlhelp to make HTML files and a HTML help project
22 | echo. qthelp to make HTML files and a qthelp project
23 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
24 | echo. changes to make an overview over all changed/added/deprecated items
25 | echo. linkcheck to check all external links for integrity
26 | echo. doctest to run all doctests embedded in the documentation if enabled
27 | goto end
28 | )
29 |
30 | if "%1" == "clean" (
31 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
32 | del /q /s %BUILDDIR%\*
33 | goto end
34 | )
35 |
36 | if "%1" == "html" (
37 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
38 | echo.
39 | echo.Build finished. The HTML pages are in %BUILDDIR%/html.
40 | goto end
41 | )
42 |
43 | if "%1" == "dirhtml" (
44 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
45 | echo.
46 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
47 | goto end
48 | )
49 |
50 | if "%1" == "pickle" (
51 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
52 | echo.
53 | echo.Build finished; now you can process the pickle files.
54 | goto end
55 | )
56 |
57 | if "%1" == "json" (
58 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
59 | echo.
60 | echo.Build finished; now you can process the JSON files.
61 | goto end
62 | )
63 |
64 | if "%1" == "htmlhelp" (
65 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
66 | echo.
67 | echo.Build finished; now you can run HTML Help Workshop with the ^
68 | .hhp project file in %BUILDDIR%/htmlhelp.
69 | goto end
70 | )
71 |
72 | if "%1" == "qthelp" (
73 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
74 | echo.
75 | echo.Build finished; now you can run "qcollectiongenerator" with the ^
76 | .qhcp project file in %BUILDDIR%/qthelp, like this:
77 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\python_speech_features.qhcp
78 | echo.To view the help file:
79 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\python_speech_features.ghc
80 | goto end
81 | )
82 |
83 | if "%1" == "latex" (
84 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
85 | echo.
86 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
87 | goto end
88 | )
89 |
90 | if "%1" == "changes" (
91 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
92 | echo.
93 | echo.The overview file is in %BUILDDIR%/changes.
94 | goto end
95 | )
96 |
97 | if "%1" == "linkcheck" (
98 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
99 | echo.
100 | echo.Link check complete; look for any errors in the above output ^
101 | or in %BUILDDIR%/linkcheck/output.txt.
102 | goto end
103 | )
104 |
105 | if "%1" == "doctest" (
106 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
107 | echo.
108 | echo.Testing of doctests in the sources finished, look at the ^
109 | results in %BUILDDIR%/doctest/output.txt.
110 | goto end
111 | )
112 |
113 | :end
114 |
--------------------------------------------------------------------------------
/docs/source/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # python_speech_features documentation build configuration file, created by
4 | # sphinx-quickstart on Thu Oct 31 16:49:58 2013.
5 | #
6 | # This file is execfile()d with the current directory set to its containing dir.
7 | #
8 | # Note that not all possible configuration values are present in this
9 | # autogenerated file.
10 | #
11 | # All configuration values have a default; values that are commented out
12 | # serve to show the default.
13 |
14 | import sys, os
15 |
16 | import mock
17 |
18 | MOCK_MODULES = ['numpy', 'scipy', 'scipy.fftpack']
19 | for mod_name in MOCK_MODULES:
20 | sys.modules[mod_name] = mock.Mock()
21 |
22 | # If extensions (or modules to document with autodoc) are in another directory,
23 | # add these directories to sys.path here. If the directory is relative to the
24 | # documentation root, use os.path.abspath to make it absolute, like shown here.
25 | sys.path.insert(0,os.path.abspath('../..'))
26 |
27 | # -- General configuration -----------------------------------------------------
28 |
29 | # Add any Sphinx extension module names here, as strings. They can be extensions
30 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
31 | extensions = ['sphinx.ext.autodoc']
32 |
33 | # Add any paths that contain templates here, relative to this directory.
34 | templates_path = ['_templates']
35 |
36 | # The suffix of source filenames.
37 | source_suffix = '.rst'
38 |
39 | # The encoding of source files.
40 | #source_encoding = 'utf-8'
41 |
42 | # The master toctree document.
43 | master_doc = 'index'
44 |
45 | # General information about the project.
46 | project = u'python_speech_features'
47 | copyright = u'2013, James Lyons'
48 |
49 | # The version info for the project you're documenting, acts as replacement for
50 | # |version| and |release|, also used in various other places throughout the
51 | # built documents.
52 | #
53 | # The short X.Y version.
54 | version = '0.1.0'
55 | # The full version, including alpha/beta/rc tags.
56 | release = '0.1.0'
57 |
58 | # The language for content autogenerated by Sphinx. Refer to documentation
59 | # for a list of supported languages.
60 | #language = None
61 |
62 | # There are two options for replacing |today|: either, you set today to some
63 | # non-false value, then it is used:
64 | #today = ''
65 | # Else, today_fmt is used as the format for a strftime call.
66 | #today_fmt = '%B %d, %Y'
67 |
68 | # List of documents that shouldn't be included in the build.
69 | #unused_docs = []
70 |
71 | # List of directories, relative to source directory, that shouldn't be searched
72 | # for source files.
73 | exclude_trees = []
74 |
75 | # The reST default role (used for this markup: `text`) to use for all documents.
76 | #default_role = None
77 |
78 | # If true, '()' will be appended to :func: etc. cross-reference text.
79 | #add_function_parentheses = True
80 |
81 | # If true, the current module name will be prepended to all description
82 | # unit titles (such as .. function::).
83 | #add_module_names = True
84 |
85 | # If true, sectionauthor and moduleauthor directives will be shown in the
86 | # output. They are ignored by default.
87 | #show_authors = False
88 |
89 | # The name of the Pygments (syntax highlighting) style to use.
90 | pygments_style = 'sphinx'
91 |
92 | # A list of ignored prefixes for module index sorting.
93 | #modindex_common_prefix = []
94 |
95 |
96 | # -- Options for HTML output ---------------------------------------------------
97 |
98 | # The theme to use for HTML and HTML Help pages. Major themes that come with
99 | # Sphinx are currently 'default' and 'sphinxdoc'.
100 | html_theme = 'default'
101 |
102 | # Theme options are theme-specific and customize the look and feel of a theme
103 | # further. For a list of options available for each theme, see the
104 | # documentation.
105 | #html_theme_options = {}
106 |
107 | # Add any paths that contain custom themes here, relative to this directory.
108 | #html_theme_path = []
109 |
110 | # The name for this set of Sphinx documents. If None, it defaults to
111 | # " v documentation".
112 | #html_title = None
113 |
114 | # A shorter title for the navigation bar. Default is the same as html_title.
115 | #html_short_title = None
116 |
117 | # The name of an image file (relative to this directory) to place at the top
118 | # of the sidebar.
119 | #html_logo = None
120 |
121 | # The name of an image file (within the static path) to use as favicon of the
122 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
123 | # pixels large.
124 | #html_favicon = None
125 |
126 | # Add any paths that contain custom static files (such as style sheets) here,
127 | # relative to this directory. They are copied after the builtin static files,
128 | # so a file named "default.css" will overwrite the builtin "default.css".
129 | html_static_path = ['_static']
130 |
131 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
132 | # using the given strftime format.
133 | #html_last_updated_fmt = '%b %d, %Y'
134 |
135 | # If true, SmartyPants will be used to convert quotes and dashes to
136 | # typographically correct entities.
137 | #html_use_smartypants = True
138 |
139 | # Custom sidebar templates, maps document names to template names.
140 | #html_sidebars = {}
141 |
142 | # Additional templates that should be rendered to pages, maps page names to
143 | # template names.
144 | #html_additional_pages = {}
145 |
146 | # If false, no module index is generated.
147 | #html_use_modindex = True
148 |
149 | # If false, no index is generated.
150 | #html_use_index = True
151 |
152 | # If true, the index is split into individual pages for each letter.
153 | #html_split_index = False
154 |
155 | # If true, links to the reST sources are added to the pages.
156 | #html_show_sourcelink = True
157 |
158 | # If true, an OpenSearch description file will be output, and all pages will
159 | # contain a tag referring to it. The value of this option must be the
160 | # base URL from which the finished HTML is served.
161 | #html_use_opensearch = ''
162 |
163 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
164 | #html_file_suffix = ''
165 |
166 | # Output file base name for HTML help builder.
167 | htmlhelp_basename = 'python_speech_featuresdoc'
168 |
169 |
170 | # -- Options for LaTeX output --------------------------------------------------
171 |
172 | # The paper size ('letter' or 'a4').
173 | #latex_paper_size = 'letter'
174 |
175 | # The font size ('10pt', '11pt' or '12pt').
176 | #latex_font_size = '10pt'
177 |
178 | # Grouping the document tree into LaTeX files. List of tuples
179 | # (source start file, target name, title, author, documentclass [howto/manual]).
180 | latex_documents = [
181 | ('index', 'python_speech_features.tex', u'python\\_speech\\_features Documentation',
182 | u'James Lyons', 'manual'),
183 | ]
184 |
185 | # The name of an image file (relative to this directory) to place at the top of
186 | # the title page.
187 | #latex_logo = None
188 |
189 | # For "manual" documents, if this is true, then toplevel headings are parts,
190 | # not chapters.
191 | #latex_use_parts = False
192 |
193 | # Additional stuff for the LaTeX preamble.
194 | #latex_preamble = ''
195 |
196 | # Documents to append as an appendix to all manuals.
197 | #latex_appendices = []
198 |
199 | # If false, no module index is generated.
200 | #latex_use_modindex = True
201 |
202 | autodoc_member_order = 'bysource'
203 |
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. python_speech_features documentation master file, created by
2 | sphinx-quickstart on Thu Oct 31 16:49:58 2013.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to python_speech_features's documentation!
7 | ==================================================
8 |
9 | This library provides common speech features for ASR including MFCCs and filterbank energies.
10 | If you are not sure what MFCCs are, and would like to know more have a look at this MFCC tutorial:
11 | http://www.practicalcryptography.com/miscellaneous/machine-learning/guide-mel-frequency-cepstral-coefficients-mfccs/.
12 |
13 | You will need numpy and scipy to run these files. The code for this project is available at https://github.com/jameslyons/python_speech_features .
14 |
15 | Supported features:
16 |
17 | - :py:meth:`python_speech_features.mfcc` - Mel Frequency Cepstral Coefficients
18 | - :py:meth:`python_speech_features.fbank` - Filterbank Energies
19 | - :py:meth:`python_speech_features.logfbank` - Log Filterbank Energies
20 | - :py:meth:`python_speech_features.ssc` - Spectral Subband Centroids
21 |
22 | To use MFCC features::
23 |
24 | from python_speech_features import mfcc
25 | from python_speech_features import logfbank
26 | import scipy.io.wavfile as wav
27 |
28 | (rate,sig) = wav.read("file.wav")
29 | mfcc_feat = mfcc(sig,rate)
30 | fbank_feat = logfbank(sig,rate)
31 |
32 | print(fbank_feat[1:3,:])
33 |
34 | From here you can write the features to a file etc.
35 |
36 | Functions provided in python_speech_features module
37 | -------------------------------------
38 |
39 | .. automodule:: python_speech_features.base
40 | :members:
41 |
42 |
43 | Functions provided in sigproc module
44 | ------------------------------------
45 | .. automodule:: python_speech_features.sigproc
46 | :members:
47 |
48 |
49 | Indices and tables
50 | ==================
51 |
52 | * :ref:`genindex`
53 | * :ref:`search`
54 |
55 |
--------------------------------------------------------------------------------
/english.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jameslyons/python_speech_features/e280ac2b5797a3445c34820b0110885cd6609e5f/english.wav
--------------------------------------------------------------------------------
/example.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from python_speech_features import mfcc
4 | from python_speech_features import delta
5 | from python_speech_features import logfbank
6 | import scipy.io.wavfile as wav
7 |
8 | (rate,sig) = wav.read("english.wav")
9 | mfcc_feat = mfcc(sig,rate)
10 | d_mfcc_feat = delta(mfcc_feat, 2)
11 | fbank_feat = logfbank(sig,rate)
12 |
13 | print(fbank_feat[1:3,:])
14 |
--------------------------------------------------------------------------------
/python_speech_features/__init__.py:
--------------------------------------------------------------------------------
1 | from .base import *
2 |
--------------------------------------------------------------------------------
/python_speech_features/base.py:
--------------------------------------------------------------------------------
1 | # calculate filterbank features. Provides e.g. fbank and mfcc features for use in ASR applications
2 | # Author: James Lyons 2012
3 | from __future__ import division
4 | import numpy
5 | from python_speech_features import sigproc
6 | from scipy.fftpack import dct
7 |
8 | def calculate_nfft(samplerate, winlen):
9 | """Calculates the FFT size as a power of two greater than or equal to
10 | the number of samples in a single window length.
11 |
12 | Having an FFT less than the window length loses precision by dropping
13 | many of the samples; a longer FFT than the window allows zero-padding
14 | of the FFT buffer which is neutral in terms of frequency domain conversion.
15 |
16 | :param samplerate: The sample rate of the signal we are working with, in Hz.
17 | :param winlen: The length of the analysis window in seconds.
18 | """
19 | window_length_samples = winlen * samplerate
20 | nfft = 1
21 | while nfft < window_length_samples:
22 | nfft *= 2
23 | return nfft
24 |
25 | def mfcc(signal,samplerate=16000,winlen=0.025,winstep=0.01,numcep=13,
26 | nfilt=26,nfft=None,lowfreq=0,highfreq=None,preemph=0.97,ceplifter=22,appendEnergy=True,
27 | winfunc=lambda x:numpy.ones((x,))):
28 | """Compute MFCC features from an audio signal.
29 |
30 | :param signal: the audio signal from which to compute features. Should be an N*1 array
31 | :param samplerate: the sample rate of the signal we are working with, in Hz.
32 | :param winlen: the length of the analysis window in seconds. Default is 0.025s (25 milliseconds)
33 | :param winstep: the step between successive windows in seconds. Default is 0.01s (10 milliseconds)
34 | :param numcep: the number of cepstrum to return, default 13
35 | :param nfilt: the number of filters in the filterbank, default 26.
36 | :param nfft: the FFT size. Default is None, which uses the calculate_nfft function to choose the smallest size that does not drop sample data.
37 | :param lowfreq: lowest band edge of mel filters. In Hz, default is 0.
38 | :param highfreq: highest band edge of mel filters. In Hz, default is samplerate/2
39 | :param preemph: apply preemphasis filter with preemph as coefficient. 0 is no filter. Default is 0.97.
40 | :param ceplifter: apply a lifter to final cepstral coefficients. 0 is no lifter. Default is 22.
41 | :param appendEnergy: if this is true, the zeroth cepstral coefficient is replaced with the log of the total frame energy.
42 | :param winfunc: the analysis window to apply to each frame. By default no window is applied. You can use numpy window functions here e.g. winfunc=numpy.hamming
43 | :returns: A numpy array of size (NUMFRAMES by numcep) containing features. Each row holds 1 feature vector.
44 | """
45 | nfft = nfft or calculate_nfft(samplerate, winlen)
46 | feat,energy = fbank(signal,samplerate,winlen,winstep,nfilt,nfft,lowfreq,highfreq,preemph,winfunc)
47 | feat = numpy.log(feat)
48 | feat = dct(feat, type=2, axis=1, norm='ortho')[:,:numcep]
49 | feat = lifter(feat,ceplifter)
50 | if appendEnergy: feat[:,0] = numpy.log(energy) # replace first cepstral coefficient with log of frame energy
51 | return feat
52 |
53 | def fbank(signal,samplerate=16000,winlen=0.025,winstep=0.01,
54 | nfilt=26,nfft=512,lowfreq=0,highfreq=None,preemph=0.97,
55 | winfunc=lambda x:numpy.ones((x,))):
56 | """Compute Mel-filterbank energy features from an audio signal.
57 |
58 | :param signal: the audio signal from which to compute features. Should be an N*1 array
59 | :param samplerate: the sample rate of the signal we are working with, in Hz.
60 | :param winlen: the length of the analysis window in seconds. Default is 0.025s (25 milliseconds)
61 | :param winstep: the step between successive windows in seconds. Default is 0.01s (10 milliseconds)
62 | :param nfilt: the number of filters in the filterbank, default 26.
63 | :param nfft: the FFT size. Default is 512.
64 | :param lowfreq: lowest band edge of mel filters. In Hz, default is 0.
65 | :param highfreq: highest band edge of mel filters. In Hz, default is samplerate/2
66 | :param preemph: apply preemphasis filter with preemph as coefficient. 0 is no filter. Default is 0.97.
67 | :param winfunc: the analysis window to apply to each frame. By default no window is applied. You can use numpy window functions here e.g. winfunc=numpy.hamming
68 | :returns: 2 values. The first is a numpy array of size (NUMFRAMES by nfilt) containing features. Each row holds 1 feature vector. The
69 | second return value is the energy in each frame (total energy, unwindowed)
70 | """
71 | highfreq= highfreq or samplerate/2
72 | signal = sigproc.preemphasis(signal,preemph)
73 | frames = sigproc.framesig(signal, winlen*samplerate, winstep*samplerate, winfunc)
74 | pspec = sigproc.powspec(frames,nfft)
75 | energy = numpy.sum(pspec,1) # this stores the total energy in each frame
76 | energy = numpy.where(energy == 0,numpy.finfo(float).eps,energy) # if energy is zero, we get problems with log
77 |
78 | fb = get_filterbanks(nfilt,nfft,samplerate,lowfreq,highfreq)
79 | feat = numpy.dot(pspec,fb.T) # compute the filterbank energies
80 | feat = numpy.where(feat == 0,numpy.finfo(float).eps,feat) # if feat is zero, we get problems with log
81 |
82 | return feat,energy
83 |
84 | def logfbank(signal,samplerate=16000,winlen=0.025,winstep=0.01,
85 | nfilt=26,nfft=512,lowfreq=0,highfreq=None,preemph=0.97,
86 | winfunc=lambda x:numpy.ones((x,))):
87 | """Compute log Mel-filterbank energy features from an audio signal.
88 |
89 | :param signal: the audio signal from which to compute features. Should be an N*1 array
90 | :param samplerate: the sample rate of the signal we are working with, in Hz.
91 | :param winlen: the length of the analysis window in seconds. Default is 0.025s (25 milliseconds)
92 | :param winstep: the step between successive windows in seconds. Default is 0.01s (10 milliseconds)
93 | :param nfilt: the number of filters in the filterbank, default 26.
94 | :param nfft: the FFT size. Default is 512.
95 | :param lowfreq: lowest band edge of mel filters. In Hz, default is 0.
96 | :param highfreq: highest band edge of mel filters. In Hz, default is samplerate/2
97 | :param preemph: apply preemphasis filter with preemph as coefficient. 0 is no filter. Default is 0.97.
98 | :param winfunc: the analysis window to apply to each frame. By default no window is applied. You can use numpy window functions here e.g. winfunc=numpy.hamming
99 | :returns: A numpy array of size (NUMFRAMES by nfilt) containing features. Each row holds 1 feature vector.
100 | """
101 | feat,energy = fbank(signal,samplerate,winlen,winstep,nfilt,nfft,lowfreq,highfreq,preemph,winfunc)
102 | return numpy.log(feat)
103 |
104 | def ssc(signal,samplerate=16000,winlen=0.025,winstep=0.01,
105 | nfilt=26,nfft=512,lowfreq=0,highfreq=None,preemph=0.97,
106 | winfunc=lambda x:numpy.ones((x,))):
107 | """Compute Spectral Subband Centroid features from an audio signal.
108 |
109 | :param signal: the audio signal from which to compute features. Should be an N*1 array
110 | :param samplerate: the sample rate of the signal we are working with, in Hz.
111 | :param winlen: the length of the analysis window in seconds. Default is 0.025s (25 milliseconds)
112 | :param winstep: the step between successive windows in seconds. Default is 0.01s (10 milliseconds)
113 | :param nfilt: the number of filters in the filterbank, default 26.
114 | :param nfft: the FFT size. Default is 512.
115 | :param lowfreq: lowest band edge of mel filters. In Hz, default is 0.
116 | :param highfreq: highest band edge of mel filters. In Hz, default is samplerate/2
117 | :param preemph: apply preemphasis filter with preemph as coefficient. 0 is no filter. Default is 0.97.
118 | :param winfunc: the analysis window to apply to each frame. By default no window is applied. You can use numpy window functions here e.g. winfunc=numpy.hamming
119 | :returns: A numpy array of size (NUMFRAMES by nfilt) containing features. Each row holds 1 feature vector.
120 | """
121 | highfreq= highfreq or samplerate/2
122 | signal = sigproc.preemphasis(signal,preemph)
123 | frames = sigproc.framesig(signal, winlen*samplerate, winstep*samplerate, winfunc)
124 | pspec = sigproc.powspec(frames,nfft)
125 | pspec = numpy.where(pspec == 0,numpy.finfo(float).eps,pspec) # if things are all zeros we get problems
126 |
127 | fb = get_filterbanks(nfilt,nfft,samplerate,lowfreq,highfreq)
128 | feat = numpy.dot(pspec,fb.T) # compute the filterbank energies
129 | R = numpy.tile(numpy.linspace(1,samplerate/2,numpy.size(pspec,1)),(numpy.size(pspec,0),1))
130 |
131 | return numpy.dot(pspec*R,fb.T) / feat
132 |
133 | def hz2mel(hz):
134 | """Convert a value in Hertz to Mels
135 |
136 | :param hz: a value in Hz. This can also be a numpy array, conversion proceeds element-wise.
137 | :returns: a value in Mels. If an array was passed in, an identical sized array is returned.
138 | """
139 | return 2595 * numpy.log10(1+hz/700.)
140 |
141 | def mel2hz(mel):
142 | """Convert a value in Mels to Hertz
143 |
144 | :param mel: a value in Mels. This can also be a numpy array, conversion proceeds element-wise.
145 | :returns: a value in Hertz. If an array was passed in, an identical sized array is returned.
146 | """
147 | return 700*(10**(mel/2595.0)-1)
148 |
149 | def get_filterbanks(nfilt=20,nfft=512,samplerate=16000,lowfreq=0,highfreq=None):
150 | """Compute a Mel-filterbank. The filters are stored in the rows, the columns correspond
151 | to fft bins. The filters are returned as an array of size nfilt * (nfft/2 + 1)
152 |
153 | :param nfilt: the number of filters in the filterbank, default 20.
154 | :param nfft: the FFT size. Default is 512.
155 | :param samplerate: the sample rate of the signal we are working with, in Hz. Affects mel spacing.
156 | :param lowfreq: lowest band edge of mel filters, default 0 Hz
157 | :param highfreq: highest band edge of mel filters, default samplerate/2
158 | :returns: A numpy array of size nfilt * (nfft/2 + 1) containing filterbank. Each row holds 1 filter.
159 | """
160 | highfreq= highfreq or samplerate/2
161 | assert highfreq <= samplerate/2, "highfreq is greater than samplerate/2"
162 |
163 | # compute points evenly spaced in mels
164 | lowmel = hz2mel(lowfreq)
165 | highmel = hz2mel(highfreq)
166 | melpoints = numpy.linspace(lowmel,highmel,nfilt+2)
167 | # our points are in Hz, but we use fft bins, so we have to convert
168 | # from Hz to fft bin number
169 | bin = numpy.floor((nfft+1)*mel2hz(melpoints)/samplerate)
170 |
171 | fbank = numpy.zeros([nfilt,nfft//2+1])
172 | for j in range(0,nfilt):
173 | for i in range(int(bin[j]), int(bin[j+1])):
174 | fbank[j,i] = (i - bin[j]) / (bin[j+1]-bin[j])
175 | for i in range(int(bin[j+1]), int(bin[j+2])):
176 | fbank[j,i] = (bin[j+2]-i) / (bin[j+2]-bin[j+1])
177 | return fbank
178 |
179 | def lifter(cepstra, L=22):
180 | """Apply a cepstral lifter the the matrix of cepstra. This has the effect of increasing the
181 | magnitude of the high frequency DCT coeffs.
182 |
183 | :param cepstra: the matrix of mel-cepstra, will be numframes * numcep in size.
184 | :param L: the liftering coefficient to use. Default is 22. L <= 0 disables lifter.
185 | """
186 | if L > 0:
187 | nframes,ncoeff = numpy.shape(cepstra)
188 | n = numpy.arange(ncoeff)
189 | lift = 1 + (L/2.)*numpy.sin(numpy.pi*n/L)
190 | return lift*cepstra
191 | else:
192 | # values of L <= 0, do nothing
193 | return cepstra
194 |
195 | def delta(feat, N):
196 | """Compute delta features from a feature vector sequence.
197 |
198 | :param feat: A numpy array of size (NUMFRAMES by number of features) containing features. Each row holds 1 feature vector.
199 | :param N: For each frame, calculate delta features based on preceding and following N frames
200 | :returns: A numpy array of size (NUMFRAMES by number of features) containing delta features. Each row holds 1 delta feature vector.
201 | """
202 | if N < 1:
203 | raise ValueError('N must be an integer >= 1')
204 | NUMFRAMES = len(feat)
205 | denominator = 2 * sum([i**2 for i in range(1, N+1)])
206 | delta_feat = numpy.empty_like(feat)
207 | padded = numpy.pad(feat, ((N, N), (0, 0)), mode='edge') # padded version of feat
208 | for t in range(NUMFRAMES):
209 | delta_feat[t] = numpy.dot(numpy.arange(-N, N+1), padded[t : t+2*N+1]) / denominator # [t : t+2*N+1] == [(N+t)-N : (N+t)+N+1]
210 | return delta_feat
211 |
--------------------------------------------------------------------------------
/python_speech_features/sigproc.py:
--------------------------------------------------------------------------------
1 | # This file includes routines for basic signal processing including framing and computing power spectra.
2 | # Author: James Lyons 2012
3 | import decimal
4 |
5 | import numpy
6 | import math
7 | import logging
8 |
9 |
10 | def round_half_up(number):
11 | return int(decimal.Decimal(number).quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP))
12 |
13 |
14 | def rolling_window(a, window, step=1):
15 | # http://ellisvalentiner.com/post/2017-03-21-np-strides-trick
16 | shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
17 | strides = a.strides + (a.strides[-1],)
18 | return numpy.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)[::step]
19 |
20 |
21 | def framesig(sig, frame_len, frame_step, winfunc=lambda x: numpy.ones((x,)), stride_trick=True):
22 | """Frame a signal into overlapping frames.
23 |
24 | :param sig: the audio signal to frame.
25 | :param frame_len: length of each frame measured in samples.
26 | :param frame_step: number of samples after the start of the previous frame that the next frame should begin.
27 | :param winfunc: the analysis window to apply to each frame. By default no window is applied.
28 | :param stride_trick: use stride trick to compute the rolling window and window multiplication faster
29 | :returns: an array of frames. Size is NUMFRAMES by frame_len.
30 | """
31 | slen = len(sig)
32 | frame_len = int(round_half_up(frame_len))
33 | frame_step = int(round_half_up(frame_step))
34 | if slen <= frame_len:
35 | numframes = 1
36 | else:
37 | numframes = 1 + int(math.ceil((1.0 * slen - frame_len) / frame_step))
38 |
39 | padlen = int((numframes - 1) * frame_step + frame_len)
40 |
41 | zeros = numpy.zeros((padlen - slen,))
42 | padsignal = numpy.concatenate((sig, zeros))
43 | if stride_trick:
44 | win = winfunc(frame_len)
45 | frames = rolling_window(padsignal, window=frame_len, step=frame_step)
46 | else:
47 | indices = numpy.tile(numpy.arange(0, frame_len), (numframes, 1)) + numpy.tile(
48 | numpy.arange(0, numframes * frame_step, frame_step), (frame_len, 1)).T
49 | indices = numpy.array(indices, dtype=numpy.int32)
50 | frames = padsignal[indices]
51 | win = numpy.tile(winfunc(frame_len), (numframes, 1))
52 |
53 | return frames * win
54 |
55 |
56 | def deframesig(frames, siglen, frame_len, frame_step, winfunc=lambda x: numpy.ones((x,))):
57 | """Does overlap-add procedure to undo the action of framesig.
58 |
59 | :param frames: the array of frames.
60 | :param siglen: the length of the desired signal, use 0 if unknown. Output will be truncated to siglen samples.
61 | :param frame_len: length of each frame measured in samples.
62 | :param frame_step: number of samples after the start of the previous frame that the next frame should begin.
63 | :param winfunc: the analysis window to apply to each frame. By default no window is applied.
64 | :returns: a 1-D signal.
65 | """
66 | frame_len = round_half_up(frame_len)
67 | frame_step = round_half_up(frame_step)
68 | numframes = numpy.shape(frames)[0]
69 | assert numpy.shape(frames)[1] == frame_len, '"frames" matrix is wrong size, 2nd dim is not equal to frame_len'
70 |
71 | indices = numpy.tile(numpy.arange(0, frame_len), (numframes, 1)) + numpy.tile(
72 | numpy.arange(0, numframes * frame_step, frame_step), (frame_len, 1)).T
73 | indices = numpy.array(indices, dtype=numpy.int32)
74 | padlen = (numframes - 1) * frame_step + frame_len
75 |
76 | if siglen <= 0: siglen = padlen
77 |
78 | rec_signal = numpy.zeros((padlen,))
79 | window_correction = numpy.zeros((padlen,))
80 | win = winfunc(frame_len)
81 |
82 | for i in range(0, numframes):
83 | window_correction[indices[i, :]] = window_correction[
84 | indices[i, :]] + win + 1e-15 # add a little bit so it is never zero
85 | rec_signal[indices[i, :]] = rec_signal[indices[i, :]] + frames[i, :]
86 |
87 | rec_signal = rec_signal / window_correction
88 | return rec_signal[0:siglen]
89 |
90 |
91 | def magspec(frames, NFFT):
92 | """Compute the magnitude spectrum of each frame in frames. If frames is an NxD matrix, output will be Nx(NFFT/2+1).
93 |
94 | :param frames: the array of frames. Each row is a frame.
95 | :param NFFT: the FFT length to use. If NFFT > frame_len, the frames are zero-padded.
96 | :returns: If frames is an NxD matrix, output will be Nx(NFFT/2+1). Each row will be the magnitude spectrum of the corresponding frame.
97 | """
98 | if numpy.shape(frames)[1] > NFFT:
99 | logging.warn(
100 | 'frame length (%d) is greater than FFT size (%d), frame will be truncated. Increase NFFT to avoid.',
101 | numpy.shape(frames)[1], NFFT)
102 | complex_spec = numpy.fft.rfft(frames, NFFT)
103 | return numpy.absolute(complex_spec)
104 |
105 |
106 | def powspec(frames, NFFT):
107 | """Compute the power spectrum of each frame in frames. If frames is an NxD matrix, output will be Nx(NFFT/2+1).
108 |
109 | :param frames: the array of frames. Each row is a frame.
110 | :param NFFT: the FFT length to use. If NFFT > frame_len, the frames are zero-padded.
111 | :returns: If frames is an NxD matrix, output will be Nx(NFFT/2+1). Each row will be the power spectrum of the corresponding frame.
112 | """
113 | return 1.0 / NFFT * numpy.square(magspec(frames, NFFT))
114 |
115 |
116 | def logpowspec(frames, NFFT, norm=1):
117 | """Compute the log power spectrum of each frame in frames. If frames is an NxD matrix, output will be Nx(NFFT/2+1).
118 |
119 | :param frames: the array of frames. Each row is a frame.
120 | :param NFFT: the FFT length to use. If NFFT > frame_len, the frames are zero-padded.
121 | :param norm: If norm=1, the log power spectrum is normalised so that the max value (across all frames) is 0.
122 | :returns: If frames is an NxD matrix, output will be Nx(NFFT/2+1). Each row will be the log power spectrum of the corresponding frame.
123 | """
124 | ps = powspec(frames, NFFT);
125 | ps[ps <= 1e-30] = 1e-30
126 | lps = 10 * numpy.log10(ps)
127 | if norm:
128 | return lps - numpy.max(lps)
129 | else:
130 | return lps
131 |
132 |
133 | def preemphasis(signal, coeff=0.95):
134 | """perform preemphasis on the input signal.
135 |
136 | :param signal: The signal to filter.
137 | :param coeff: The preemphasis coefficient. 0 is no filter, default is 0.95.
138 | :returns: the filtered signal.
139 | """
140 | return numpy.append(signal[0], signal[1:] - coeff * signal[:-1])
141 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | --index-url https://pypi.python.org/simple/
2 |
3 | -e .
4 | mock
5 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | try:
2 | from setuptools import setup #enables develop
3 | except ImportError:
4 | from distutils.core import setup
5 |
6 | setup(name='python_speech_features',
7 | version='0.6.1',
8 | description='Python Speech Feature extraction',
9 | author='James Lyons',
10 | author_email='james.lyons0@gmail.com',
11 | license='MIT',
12 | url='https://github.com/jameslyons/python_speech_features',
13 | packages=['python_speech_features'],
14 | install_requires=[
15 | 'numpy',
16 | 'scipy',
17 | ]
18 | )
19 |
--------------------------------------------------------------------------------
/test/test_sigproc.py:
--------------------------------------------------------------------------------
1 | from python_speech_features import sigproc
2 | import unittest
3 | import numpy as np
4 | import time
5 |
6 |
7 | class test_case(unittest.TestCase):
8 | def test_frame_sig(self):
9 | n = 10000124
10 | frame_len = 37
11 | frame_step = 13
12 | x = np.random.rand(n)
13 | t0 = time.time()
14 | y_old = sigproc.framesig(x, frame_len=frame_len, frame_step=frame_step, stride_trick=False)
15 | t1 = time.time()
16 | y_new = sigproc.framesig(x, frame_len=frame_len, frame_step=frame_step, stride_trick=True)
17 | t_new = time.time() - t1
18 | t_old = t1 - t0
19 | self.assertTupleEqual(y_old.shape, y_new.shape)
20 | np.testing.assert_array_equal(y_old, y_new)
21 | self.assertLess(t_new, t_old)
22 | print('new run time %3.2f < %3.2f sec' % (t_new, t_old))
23 |
24 | def test_rolling(self):
25 | x = np.arange(10)
26 | y = sigproc.rolling_window(x, window=4, step=3)
27 | y_expected = np.array([[0, 1, 2, 3],
28 | [3, 4, 5, 6],
29 | [6, 7, 8, 9]]
30 | )
31 | y = np.testing.assert_array_equal(y, y_expected)
32 |
--------------------------------------------------------------------------------