.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/multistageinterpolation.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_multistageinterpolation.py: ========================= Multi-stage interpolation. ========================= Design a two-stage interpolation with a total interpolation factor of four. .. GENERATED FROM PYTHON SOURCE LINES 8-20 .. code-block:: Python import math import matplotlib.pyplot as plt import numpy as np from mplsignal import freqz_fir from fird.constraint import PiecewiseLinearConstraint from fird.designer import FIRDesigner from fird.objective import PiecewiseLinearObjective from fird.util import expand .. GENERATED FROM PYTHON SOURCE LINES 21-22 Obtimize stopband attentation, while keeping passband ripple below 0.01 .. GENERATED FROM PYTHON SOURCE LINES 22-25 .. code-block:: Python total_objective = PiecewiseLinearObjective([0.3, 0.7, 0.8, 1], [0, 0, 0, 0]) total_constraint = PiecewiseLinearConstraint([0, 0.2], [1, 1], [0.01]) .. GENERATED FROM PYTHON SOURCE LINES 26-27 Design first stage filter, keep passband ripple to half .. GENERATED FROM PYTHON SOURCE LINES 27-33 .. code-block:: Python firststage_objective = PiecewiseLinearObjective([0.6, 1], [0, 0]) firststage_constraint = PiecewiseLinearConstraint([0, 0.4], [1, 1], [0.01 / 2]) firststage_designer = FIRDesigner(31, firststage_objective, firststage_constraint) firststage_designer.solve() h1 = firststage_designer.get_impulse_response() .. GENERATED FROM PYTHON SOURCE LINES 34-35 Plot the magnitude response of the first-stage filter. .. GENERATED FROM PYTHON SOURCE LINES 35-49 .. code-block:: Python fig, ax = plt.subplots() freqz_fir(h1, ax=ax, style="magnitude") axins = ax.inset_axes( [0.2, 0.6, 0.6, 0.3], ) ax.set_ylim((-100, 5)) freqz_fir(h1, ax=axins, style="magnitude") axins.set_xlim(0, 0.4 * np.pi) axins.set_ylim(-0.1, 0.1) axins.xaxis.label.set_visible(False) axins.yaxis.label.set_visible(False) ax.indicate_inset_zoom(axins, edgecolor="black") fig.show() .. image-sg:: /examples/images/sphx_glr_multistageinterpolation_001.png :alt: multistageinterpolation :srcset: /examples/images/sphx_glr_multistageinterpolation_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 50-52 Design second-stage filter subject to an upsampled version of the first-stage filter. From now on, the total objective and constraint is used. .. GENERATED FROM PYTHON SOURCE LINES 52-62 .. code-block:: Python upsampled_h1 = expand(h1, 2) secondstage_designer = FIRDesigner( 17, total_objective, total_constraint, cascade_filter=upsampled_h1 ) secondstage_designer.solve() h2 = secondstage_designer.get_impulse_response() print( f"Minimum stopband attenuation: {-20 * math.log10(secondstage_designer.objective_value)} dB" ) .. rst-class:: sphx-glr-script-out .. code-block:: none Minimum stopband attenuation: 72.4954747000503 dB .. GENERATED FROM PYTHON SOURCE LINES 63-64 Plot the different filters and the total response .. GENERATED FROM PYTHON SOURCE LINES 64-83 .. code-block:: Python combined = np.convolve(upsampled_h1, h2) fig, ax = plt.subplots() freqz_fir(upsampled_h1, ax=ax, style="magnitude") freqz_fir(h2, ax=ax, style="magnitude") freqz_fir(combined, ax=ax, style="magnitude") total_objective.plot(ax=ax, plot_db=True, plot_range=True) ax.set_ylim((-140, 5)) axins = ax.inset_axes([0.1, 0.1, 0.6, 0.3]) freqz_fir(upsampled_h1, ax=axins, style="magnitude") freqz_fir(h2, ax=axins, style="magnitude") freqz_fir(combined, ax=axins, style="magnitude") total_constraint.plot(ax=axins, plot_db=True) axins.set_xlim(0, 0.2 * math.pi) axins.set_ylim(-0.1, 0.1) axins.xaxis.label.set_visible(False) axins.yaxis.label.set_visible(False) ax.indicate_inset_zoom(axins, edgecolor="black") fig.show() .. image-sg:: /examples/images/sphx_glr_multistageinterpolation_002.png :alt: multistageinterpolation :srcset: /examples/images/sphx_glr_multistageinterpolation_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none /builds/oscgu95/fird/venv/lib/python3.13/site-packages/fird/util.py:58: RuntimeWarning: divide by zero encountered in log10 return -20 * np.log10(np.abs(a)) .. GENERATED FROM PYTHON SOURCE LINES 84-86 Now redesign the first-stage filter subject to the second-stage filter. As the first-stage filter is periodic when considering the the final sample rate, the *period* argument is used. .. GENERATED FROM PYTHON SOURCE LINES 86-96 .. code-block:: Python firststage_redesigner = FIRDesigner( 31, total_objective, total_constraint, cascade_filter=h2, period=2 ) firststage_redesigner.solve() h1_new = firststage_redesigner.get_impulse_response() print( f"Minimum stopband attenuation: {-20 * math.log10(firststage_redesigner.objective_value)} dB" ) .. rst-class:: sphx-glr-script-out .. code-block:: none Minimum stopband attenuation: 72.49532277396742 dB .. GENERATED FROM PYTHON SOURCE LINES 97-98 Plot the new and old first-stage filters. .. GENERATED FROM PYTHON SOURCE LINES 98-112 .. code-block:: Python fig, ax = plt.subplots() freqz_fir(h1_new, ax=ax, style="magnitude") freqz_fir(h1, ax=ax, style="magnitude") ax.set_ylim((-100, 5)) axins = ax.inset_axes([0.2, 0.6, 0.6, 0.3]) freqz_fir(h1_new, ax=axins, style="magnitude") freqz_fir(h1, ax=axins, style="magnitude") axins.set_xlim(0, 0.4 * math.pi) axins.set_ylim(-0.1, 0.1) axins.xaxis.label.set_visible(False) axins.yaxis.label.set_visible(False) ax.indicate_inset_zoom(axins, edgecolor="black") fig.show() .. image-sg:: /examples/images/sphx_glr_multistageinterpolation_003.png :alt: multistageinterpolation :srcset: /examples/images/sphx_glr_multistageinterpolation_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 113-114 The new first-stage filter does not lead to an improved total response. .. GENERATED FROM PYTHON SOURCE LINES 114-135 .. code-block:: Python upsampled_h1_new = expand(h1_new, 2) combined_new = np.convolve(upsampled_h1_new, h2) fig, ax = plt.subplots() freqz_fir(upsampled_h1_new, ax=ax, style="magnitude") freqz_fir(h2, ax=ax, style="magnitude") freqz_fir(combined_new, ax=ax, style="magnitude") total_objective.plot(ax=ax, plot_db=True, plot_range=True) ax.set_ylim((-140, 5)) axins = ax.inset_axes([0.1, 0.1, 0.6, 0.3]) freqz_fir(upsampled_h1_new, ax=axins, style="magnitude") freqz_fir(h2, ax=axins, style="magnitude") freqz_fir(combined_new, ax=axins, style="magnitude") total_constraint.plot(ax=axins, plot_db=True) axins.set_xlim(0, 0.2 * np.pi) axins.set_ylim(-0.1, 0.1) axins.xaxis.label.set_visible(False) axins.yaxis.label.set_visible(False) ax.indicate_inset_zoom(axins, edgecolor="black") fig.show() .. image-sg:: /examples/images/sphx_glr_multistageinterpolation_004.png :alt: multistageinterpolation :srcset: /examples/images/sphx_glr_multistageinterpolation_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 136-137 Redesign second-stage filter subject to an upsampled version of the redesigned first-stage filter. .. GENERATED FROM PYTHON SOURCE LINES 137-146 .. code-block:: Python secondstage_redesigner = FIRDesigner( 17, total_objective, total_constraint, cascade_filter=upsampled_h1_new ) secondstage_redesigner.solve() h2_new = secondstage_redesigner.get_impulse_response() print( f"Minimum stopband attenuation: {-20 * math.log10(secondstage_redesigner.objective_value)} dB" ) .. rst-class:: sphx-glr-script-out .. code-block:: none Minimum stopband attenuation: 73.25777146258964 dB .. GENERATED FROM PYTHON SOURCE LINES 147-148 Plot the different filters and the total response. .. GENERATED FROM PYTHON SOURCE LINES 148-167 .. code-block:: Python combined = np.convolve(upsampled_h1_new, h2_new) fig, ax = plt.subplots() freqz_fir(upsampled_h1_new, ax=ax, style="magnitude") freqz_fir(h2_new, ax=ax, style="magnitude") freqz_fir(combined, ax=ax, style="magnitude") total_objective.plot(ax=ax, plot_db=True, plot_range=True) ax.set_ylim((-140, 5)) axins = ax.inset_axes([0.1, 0.1, 0.6, 0.3]) freqz_fir(upsampled_h1_new, ax=axins, style="magnitude") freqz_fir(h2_new, ax=axins, style="magnitude") freqz_fir(combined, ax=axins, style="magnitude") total_constraint.plot(ax=axins, plot_db=True) axins.set_xlim(0, 0.2 * math.pi) axins.set_ylim(-0.1, 0.1) axins.xaxis.label.set_visible(False) axins.yaxis.label.set_visible(False) ax.indicate_inset_zoom(axins, edgecolor="black") fig.show() .. image-sg:: /examples/images/sphx_glr_multistageinterpolation_005.png :alt: multistageinterpolation :srcset: /examples/images/sphx_glr_multistageinterpolation_005.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 168-170 It may now be possible to obtain a slightly better second-stage filter and so on. However, as the combined filter is a non-convex problem, it may not converge to the global minimum. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.299 seconds) .. _sphx_glr_download_examples_multistageinterpolation.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: multistageinterpolation.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: multistageinterpolation.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: multistageinterpolation.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_