%23%20gallery_category%3A%20Allpass%20FDN%20Examples%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.23.13%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20Allpass%20FDN%20embedded%20in%20a%20larger%20FDN%0A%0A%20%20%20%20Single%20input%2C%20stereo%20output.%20The%20signal%20flow%20is%3A%0A%0A%20%20%20%20**gain%20(1%E2%86%92N)**%20%E2%86%92%20**input%20delay**%20%E2%86%92%20**Recursion(**%20feedforward%20%3D%20**allpass%20MIMO%20FDN**%20%2B%20**attenuation%20filter**%2C%20feedback%20%3D%20**main%20delays**%20**)**%20%E2%86%92%20**output%20delay**%20%E2%86%92%20**gain%20(N%E2%86%922)**%0A%0A%20%20%20%20The%20inner%20**allpass%20MIMO%20FDN**%20is%20a%20**homogeneous%20allpass%20FDN**%20(random%20delays%2C%20diagonal%20gain%20G%2C%20orthogonal%20U%2C%20A%20%3D%20G%20%40%20U%2C%20completed%20with%20**complete_fdn**).%20It%20is%20placed%20in%20the%20feedforward%20path%20of%20the%20recursion%2C%20followed%20by%20an%20attenuation%20filter%3B%20the%20feedback%20path%20is%20the%20main%20delay%20lines.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Setup%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20plotly.io%20as%20pio%0A%0A%20%20%20%20pio.renderers.default%20%3D%20%22sphinx_gallery%22%20%20%23%20interactive%20in%20Jupyter%20%2B%20docs%20HTML%0A%20%20%20%20from%20collections%20import%20OrderedDict%0A%0A%20%20%20%20from%20flamo.processor%20import%20dsp%2C%20system%0A%0A%20%20%20%20import%20pyFDN%0A%20%20%20%20from%20pyFDN.auxiliary.flamo%20import%20delay_module%2C%20gain_module%2C%20sos_filter_module%0A%0A%20%20%20%20np.random.seed(10)%0A%20%20%20%20Fs%20%3D%2048000%0A%20%20%20%20nfft%20%3D%202**17%0A%20%20%20%20N%20%3D%204%20%20%23%20number%20of%20delay%20lines%20(1%E2%86%92N%20input%20gain%2C%20N%E2%86%922%20output%20gain)%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20Fs%2C%0A%20%20%20%20%20%20%20%20N%2C%0A%20%20%20%20%20%20%20%20OrderedDict%2C%0A%20%20%20%20%20%20%20%20delay_module%2C%0A%20%20%20%20%20%20%20%20dsp%2C%0A%20%20%20%20%20%20%20%20gain_module%2C%0A%20%20%20%20%20%20%20%20nfft%2C%0A%20%20%20%20%20%20%20%20np%2C%0A%20%20%20%20%20%20%20%20pyFDN%2C%0A%20%20%20%20%20%20%20%20sos_filter_module%2C%0A%20%20%20%20%20%20%20%20system%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%201.%20MIMO%20allpass%20FDN%20(inner%20block)%0A%0A%20%20%20%20Build%20a%20**homogeneous%20allpass%20FDN**%20(like%20in%20%60example_allpass_FDN_homogeneous_mimo%60)%3A%20random%20delays%2C%20diagonal%20gain%20**G**%2C%20random%20orthogonal%20**U**%2C%20**A%20%3D%20G%20%40%20U**%2C%20then%20**complete_fdn**%20to%20get%20B%2C%20C%2C%20D.%20Get%20the%20FLAMO%20core%20(no%20Shell)%20to%20embed%20in%20the%20recursion%20feedforward.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Fs%2C%20N%2C%20nfft%2C%20np%2C%20pyFDN)%3A%0A%20%20%20%20%23%20Homogeneous%20MIMO%20allpass%20FDN%3A%20delays%2C%20G%20%3D%20diag(g%5Edelays)%2C%20A%20%3D%20G%20%40%20U%2C%20complete_fdn%0A%20%20%20%20delays_sch%20%3D%20np.random.randint(51%2C%20300%2C%20size%3DN)%0A%20%20%20%20_g%20%3D%20pyFDN.rt_to_gain_per_sample(0.07%2C%20Fs)%0A%20%20%20%20G%20%3D%20np.diag(_g**delays_sch)%0A%20%20%20%20U%20%3D%20pyFDN.random_orthogonal(N)%0A%20%20%20%20A_sch%20%3D%20G%20%40%20U%0A%20%20%20%20B_sch%2C%20C_sch%2C%20D_sch%2C%20X%20%3D%20pyFDN.complete_fdn(A_sch%2C%20N%2C%20N)%0A%0A%20%20%20%20%23%20FLAMO%20core%20(N%E2%86%92N)%2C%20no%20Shell%20%E2%80%94%20for%20use%20inside%20the%20recursion%0A%20%20%20%20allpass_fdn_core%20%3D%20pyFDN.dss_to_flamo(%0A%20%20%20%20%20%20%20%20A_sch%2C%20B_sch%2C%20C_sch%2C%20D_sch%2C%20delays_sch%2C%20Fs%2C%20nfft%3Dnfft%2C%20shell%3DFalse%0A%20%20%20%20)%0A%20%20%20%20return%20(allpass_fdn_core%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%202.%20Delays%20and%20attenuation%0A%0A%20%20%20%20Main%20delays%20(feedback%20path)%2C%20input%20delay%2C%20output%20delay%20(all%20in%20seconds).%20Attenuation%20%3D%20diagonal%20gain%20in%20the%20feedforward%20path%20after%20the%20allpass%20FDN.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Fs%2C%20N%2C%20delay_module%2C%20nfft%2C%20np%2C%20pyFDN%2C%20sos_filter_module)%3A%0A%20%20%20%20%23%20Main%20delays%20(feedback%20path)%2C%20input%20and%20output%20delays%20%E2%80%94%20in%20seconds%0A%20%20%20%20main_delay_sec%20%3D%20np.random.uniform(0.02%2C%200.04%2C%20size%3DN)%0A%20%20%20%20input_delay_sec%20%3D%20np.linspace(0.01%2C%200.02%20*%20N%2C%20N)%20%2B%20np.random.uniform(%0A%20%20%20%20%20%20%20%200%2C%200.001%2C%20size%3DN%0A%20%20%20%20)%0A%20%20%20%20output_delay_sec%20%3D%20np.linspace(0.01%2C%200.02%2C%20N)%20%2B%20np.random.uniform(0%2C%200.001%2C%20size%3DN)%0A%0A%20%20%20%20main_delays%20%3D%20delay_module(main_delay_sec%2C%20nfft%2C%20Fs%3DFs)%0A%20%20%20%20input_delays%20%3D%20delay_module(input_delay_sec%2C%20nfft%2C%20Fs%3DFs)%0A%20%20%20%20output_delays%20%3D%20delay_module(output_delay_sec%2C%20nfft%2C%20Fs%3DFs)%0A%0A%20%20%20%20%23%20Attenuation%3A%20first-order%20absorption%2C%20canonical%20(1%2C%206%2C%20N)%20SOS%20bank.%0A%20%20%20%20main_delay_smp%20%3D%20np.round(main_delay_sec%20*%20Fs).astype(float)%0A%20%20%20%20rt_dc%2C%20rt_ny%20%3D%201.4%2C%200.3%0A%20%20%20%20sos%20%3D%20pyFDN.first_order_absorption(rt_dc%2C%20rt_ny%2C%20main_delay_smp%2C%20fs%3DFs)%0A%20%20%20%20attenuation%20%3D%20sos_filter_module(sos%2C%20nfft)%0A%20%20%20%20return%20attenuation%2C%20input_delays%2C%20main_delays%2C%20output_delays%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%203.%20Full%20chain%3A%20gain%20(1%E2%86%92N)%20%E2%86%92%20input%20delay%20%E2%86%92%20recursion%20%E2%86%92%20output%20delay%20%E2%86%92%20gain%20(N%E2%86%922)%0A%0A%20%20%20%20Recursion%3A%20**feedforward**%20%3D%20allpass%20MIMO%20FDN%20%2B%20attenuation%2C%20**feedback**%20%3D%20main%20delays.%20Then%20wrap%20in%20Shell%20for%20FFT%2FiFFT%20and%20get%20the%20impulse%20response.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20N%2C%0A%20%20%20%20OrderedDict%2C%0A%20%20%20%20allpass_fdn_core%2C%0A%20%20%20%20attenuation%2C%0A%20%20%20%20dsp%2C%0A%20%20%20%20gain_module%2C%0A%20%20%20%20input_delays%2C%0A%20%20%20%20main_delays%2C%0A%20%20%20%20nfft%2C%0A%20%20%20%20np%2C%0A%20%20%20%20output_delays%2C%0A%20%20%20%20pyFDN%2C%0A%20%20%20%20system%2C%0A)%3A%0A%20%20%20%20%23%20Input%20gain%201%E2%86%92N%2C%20output%20gain%20N%E2%86%922%20(stereo%3A%20normalize%20rows%20for%20equal%20energy)%0A%20%20%20%20B_in%20%3D%20np.ones((N%2C%201))%0A%20%20%20%20C_out%20%3D%20np.random.randn(2%2C%20N)%0A%20%20%20%20C_out%20%3D%20C_out%20%2F%20np.linalg.norm(C_out%2C%20axis%3D1%2C%20keepdims%3DTrue)%0A%0A%20%20%20%20gain_B_in%20%3D%20gain_module(B_in%2C%20nfft)%0A%20%20%20%20gain_C_out%20%3D%20gain_module(C_out%2C%20nfft)%0A%0A%20%20%20%20%23%20Recursion%3A%20fF%20%3D%20allpass%20FDN%20%E2%86%92%20attenuation%2C%20fB%20%3D%20main%20delays%0A%20%20%20%20feedforward%20%3D%20system.Series(%0A%20%20%20%20%20%20%20%20OrderedDict(%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22allpass_fdn%22%3A%20allpass_fdn_core%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22attenuation%22%3A%20attenuation%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20feedback_loop%20%3D%20system.Recursion(fF%3Dfeedforward%2C%20fB%3Dmain_delays)%0A%0A%20%20%20%20%23%20Full%20chain%0A%20%20%20%20core_chain%20%3D%20system.Series(%0A%20%20%20%20%20%20%20%20OrderedDict(%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22input_gain%22%3A%20gain_B_in%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22input_delay%22%3A%20input_delays%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22feedback_loop%22%3A%20feedback_loop%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22output_delay%22%3A%20output_delays%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22output_gain%22%3A%20gain_C_out%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%0A%20%20%20%20model%20%3D%20system.Shell(%0A%20%20%20%20%20%20%20%20core%3Dcore_chain%2C%0A%20%20%20%20%20%20%20%20input_layer%3Ddsp.FFT(nfft)%2C%0A%20%20%20%20%20%20%20%20output_layer%3Ddsp.iFFT(nfft)%2C%0A%20%20%20%20)%0A%0A%20%20%20%20ir_stereo%20%3D%20pyFDN.flamo_time_response(model).squeeze()%0A%20%20%20%20if%20ir_stereo.ndim%20%3D%3D%203%3A%0A%20%20%20%20%20%20%20%20ir_stereo%20%3D%20ir_stereo%5B0%5D%0A%20%20%20%20return%20ir_stereo%2C%20model%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Visualize%20signal%20flow%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(model%2C%20pyFDN)%3A%0A%20%20%20%20pyFDN.plot_flamo_graph(model)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%204.%20Plot%20and%20play%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Fs%2C%20ir_stereo%2C%20mo%2C%20pyFDN)%3A%0A%20%20%20%20fig%20%3D%20pyFDN.plot_impulse_response(%0A%20%20%20%20%20%20%20%20ir_stereo%5B%3A%2C%200%5D%2C%0A%20%20%20%20%20%20%20%20ir_stereo%5B%3A%2C%201%5D%2C%0A%20%20%20%20%20%20%20%20fs%3DFs%2C%0A%20%20%20%20%20%20%20%20labels%3D%5B%22L%22%2C%20%22R%22%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22Allpass%20FDN%20in%20FDN%20%E2%80%94%20stereo%20IR%22%2C%0A%20%20%20%20)%0A%0A%20%20%20%20mo.vstack(%5Bfig%2C%20mo.audio(ir_stereo.T%2C%20Fs)%5D)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
b7b5bdcb0e7f3c06f9f40fee0e53708e