%23%20gallery_category%3A%20FDN%20Design%20%26%20Analysis%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%20FDN%20design%20tradeoff%0A%0A%20%20%20%20FDN%20design%20typically%20needs%20to%20balance%20modal%20and%20echo%20density%20with%0A%20%20%20%20computational%20complexity%3A%0A%0A%20%20%20%20-%20the%20longer%20the%20delays%2C%20the%20more%20modes%2C%20but%20less%20echo%20density%3B%0A%20%20%20%20-%20the%20more%20delays%2C%20the%20higher%20modal%20and%20echo%20density%2C%20but%20more%20expensive.%0A%0A%20%20%20%20We%20compare%20a%203%C3%973%20grid%20of%20settings%3A%20FDN%20size%20%24N%20%5Cin%20%5C%7B4%2C%208%2C%2016%5C%7D%24%20and%0A%20%20%20%20short%2Fmedium%2Flong%20delays.%20Echo%20density%20(Abel%20%26%20Huang%202006)%20makes%20the%0A%20%20%20%20tradeoff%20visible%3A%20small%20%24N%24%20with%20long%20delays%20stays%20sparse%20for%20a%20long%20time.%0A%0A%20%20%20%20Reference%3A%20*Schlecht%2C%20S.%20(2020).%20FDNTB%3A%20The%20Feedback%20Delay%20Network%20Toolbox%2C%0A%20%20%20%20Proc.%2023rd%20International%20Conference%20on%20Digital%20Audio%20Effects%20(DAFx-20).*%0A%0A%20%20%20%20Original%20MATLAB%3A%20%60example_tradeoff.m%60%2C%20Sebastian%20J.%20Schlecht%2C%2006%20March%202023.%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%20%20%20%20from%20plotly.subplots%20import%20make_subplots%0A%0A%20%20%20%20import%20pyFDN%0A%0A%20%20%20%20pio.renderers.default%20%3D%20%22sphinx_gallery%22%0A%20%20%20%20return%20make_subplots%2C%20np%2C%20pyFDN%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%20Parameters%0A%0A%20%20%20%20All%20settings%20share%20the%20same%20homogeneous%20decay%20(RT%20%3D%202%20s)%2C%20so%20the%20only%0A%20%20%20%20differences%20are%20mode%20count%20and%20reflection%20density.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20pyFDN)%3A%0A%20%20%20%20np.random.seed(2)%0A%20%20%20%20fs%20%3D%2048000%0A%20%20%20%20ir_len%20%3D%202%20*%20fs%0A%20%20%20%20rt%20%3D%202.0%20%20%23%20seconds%0A%20%20%20%20gain_per_sample%20%3D%20pyFDN.rt_to_gain_per_sample(rt%2C%20fs)%0A%0A%20%20%20%20sizes%20%3D%20%5B4%2C%208%2C%2016%5D%20%20%23%20FDN%20size%3A%20small%2C%20medium%2C%20large%0A%20%20%20%20delay_scales%20%3D%20%5B300%2C%201000%2C%203000%5D%20%20%23%20delays%3A%20short%2C%20medium%2C%20long%0A%20%20%20%20base_delays%20%3D%20np.random.rand(16)%20%2B%200.5%20%20%23%20shared%20random%20delay%20pattern%0A%20%20%20%20all_delays%20%3D%20np.round(%0A%20%20%20%20%20%20%20%20base_delays%5BNone%2C%20%3A%5D%20*%20np.array(delay_scales)%5B%3A%2C%20None%5D%0A%20%20%20%20).astype(int)%0A%20%20%20%20return%20all_delays%2C%20fs%2C%20gain_per_sample%2C%20ir_len%2C%20sizes%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%20Generate%20impulse%20responses%0A%0A%20%20%20%20For%20each%20combination%2C%20an%20orthogonal%20feedback%20matrix%20is%20scaled%20by%20the%0A%20%20%20%20delay-proportional%20gains%20(homogeneous%20decay)%2C%20and%20the%20impulse%20response%20is%0A%20%20%20%20computed%20with%20%60dss_to_impz%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(all_delays%2C%20fs%2C%20gain_per_sample%2C%20ir_len%2C%20np%2C%20pyFDN%2C%20sizes)%3A%0A%20%20%20%20rirs%20%3D%20%7B%7D%0A%20%20%20%20density%20%3D%20%7B%7D%0A%20%20%20%20num_modes%20%3D%20%7B%7D%0A%20%20%20%20for%20_n%20in%20sizes%3A%0A%20%20%20%20%20%20%20%20for%20_s%20in%20range(all_delays.shape%5B0%5D)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_delays%20%3D%20all_delays%5B_s%2C%20%3A_n%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20_g%20%3D%20np.diag(gain_per_sample%20**%20_delays.astype(float))%0A%20%20%20%20%20%20%20%20%20%20%20%20_A%20%3D%20pyFDN.fdn_matrix_gallery(_n%2C%20%22orthogonal%22)%20%40%20_g%0A%20%20%20%20%20%20%20%20%20%20%20%20rirs%5B(_n%2C%20_s)%5D%20%3D%20pyFDN.dss_to_impz(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ir_len%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_delays%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_A%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20np.ones((_n%2C%201))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20np.ones((1%2C%20_n))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20np.zeros((1%2C%201))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%5B%3A%2C%200%2C%200%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20_%2C%20density%5B(_n%2C%20_s)%5D%20%3D%20pyFDN.echo_density(rirs%5B(_n%2C%20_s)%5D%2C%201024%2C%20fs%2C%200)%0A%20%20%20%20%20%20%20%20%20%20%20%20num_modes%5B(_n%2C%20_s)%5D%20%3D%20int(_delays.sum())%0A%0A%20%20%20%20for%20(_n%2C%20_s)%2C%20_modes%20in%20sorted(num_modes.items())%3A%0A%20%20%20%20%20%20%20%20_mean_delay%20%3D%20int(np.mean(all_delays%5B_s%2C%20%3A_n%5D))%0A%20%20%20%20%20%20%20%20print(f%22N%20%3D%20%7B_n%3A2d%7D%2C%20mean%20delay%20%3D%20%7B_mean_delay%3A4d%7D%3A%20%7B_modes%3A5d%7D%20modes%22)%0A%20%20%20%20return%20density%2C%20rirs%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%20Impulse%20responses%20and%20echo%20density%0A%0A%20%20%20%20Each%20panel%20shows%20the%20impulse%20response%20(gray)%20and%20its%20normalized%20echo%0A%20%20%20%20density%20profile%20(red).%20An%20echo%20density%20of%201%20means%20the%20response%20is%0A%20%20%20%20indistinguishable%20from%20Gaussian%20noise%20(fully%20mixed).%20Down%20a%20column%2C%0A%20%20%20%20longer%20delays%20slow%20down%20the%20echo%20density%20buildup%3B%20across%20a%20row%2C%20larger%0A%20%20%20%20%24N%24%20speeds%20it%20up.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(all_delays%2C%20density%2C%20fs%2C%20make_subplots%2C%20np%2C%20pyFDN%2C%20rirs%2C%20sizes)%3A%0A%20%20%20%20fig%20%3D%20make_subplots(%0A%20%20%20%20%20%20%20%20rows%3D3%2C%0A%20%20%20%20%20%20%20%20cols%3D3%2C%0A%20%20%20%20%20%20%20%20shared_xaxes%3DTrue%2C%0A%20%20%20%20%20%20%20%20subplot_titles%3D%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22N%20%3D%20%7B_n%7D%3Cbr%3Emean%20delay%20%3D%20%7Bint(np.mean(all_delays%5B_s%2C%20%3A_n%5D))%7D%22%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20_s%20in%20range(3)%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20_n%20in%20sizes%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20vertical_spacing%3D0.07%2C%0A%20%20%20%20)%0A%20%20%20%20t_axis%20%3D%20np.arange(len(next(iter(rirs.values()))))%20%2F%20fs%0A%0A%20%20%20%20for%20_s%20in%20range(3)%3A%0A%20%20%20%20%20%20%20%20for%20_col%2C%20_n%20in%20enumerate(sizes%2C%20start%3D1)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_rir%20%3D%20rirs%5B(_n%2C%20_s)%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20_dens%20%3D%20density%5B(_n%2C%20_s)%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20fig.add_trace(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pyFDN.downsampled_scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3Dt_axis%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3DpyFDN.mulaw_encode(pyFDN.peak_normalize(_rir))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20max_points%3D10_000%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22lines%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20line%3D%7B%22color%22%3A%20%22gray%22%2C%20%22width%22%3A%200.5%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20showlegend%3DFalse%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20row%3D_s%20%2B%201%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20col%3D_col%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20%20%20%20%20fig.add_trace(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pyFDN.downsampled_scatter(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3Dt_axis%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3D_dens%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20max_points%3D100%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mode%3D%22lines%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20line%3D%7B%22color%22%3A%20%22crimson%22%2C%20%22width%22%3A%201.5%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20showlegend%3DFalse%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20row%3D_s%20%2B%201%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20col%3D_col%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20fig.update_layout(%0A%20%20%20%20%20%20%20%20title%3D%22Impulse%20response%20(gray)%20and%20echo%20density%20(red)%22%2C%0A%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20height%3D720%2C%0A%20%20%20%20)%0A%20%20%20%20fig.update_xaxes(title_text%3D%22Time%20(s)%22%2C%20row%3D3)%0A%20%20%20%20fig.show()%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%20Listen%0A%0A%20%20%20%20The%20perceptual%20difference%20is%20most%20obvious%20for%20the%20small-%24N%24%20%2F%20long-delay%0A%20%20%20%20setting%20(flutter%20echoes)%20versus%20the%20large-%24N%24%20%2F%20short-delay%20setting%0A%20%20%20%20(smooth%20reverberation).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(all_delays%2C%20fs%2C%20mo%2C%20np%2C%20pyFDN%2C%20rirs%2C%20sizes)%3A%0A%20%20%20%20_delay_labels%20%3D%20%5B%22short%22%2C%20%22medium%22%2C%20%22long%22%5D%0A%20%20%20%20_rows%20%3D%20%5B%5D%0A%20%20%20%20for%20_s%2C%20_delay_label%20in%20enumerate(_delay_labels)%3A%0A%20%20%20%20%20%20%20%20_players%20%3D%20%5B%5D%0A%20%20%20%20%20%20%20%20for%20_n%20in%20sizes%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_mean_delay%20%3D%20int(np.mean(all_delays%5B_s%2C%20%3A_n%5D))%0A%20%20%20%20%20%20%20%20%20%20%20%20_players.append(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.vstack(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22**N%20%3D%20%7B_n%7D%2C%20%7B_delay_label%7D%20delays**%20%20%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22mean%20%3D%20%7B_mean_delay%7D%20samples%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20mo.audio(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20np.asarray(0.5%20*%20pyFDN.peak_normalize(rirs%5B(_n%2C%20_s)%5D))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20rate%3Dfs%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20).style(%7B%22width%22%3A%20%22100%25%22%2C%20%22zoom%22%3A%20%220.62%22%7D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gap%3D0.4%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20).style(%7B%22min-width%22%3A%20%22110px%22%2C%20%22flex%22%3A%20%221%201%20110px%22%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20_rows.append(mo.hstack(_players%2C%20wrap%3DTrue%2C%20gap%3D0.1))%0A%0A%20%20%20%20mo.vstack(_rows%2C%20gap%3D0.1)%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
00238a7feaf0db1339368e3682bea7d3