%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%20Colorless%20FDN%0A%0A%20%20%20%20FDN%20optimized%20for%20reduced%20metallic%20ringing%20(perceptually%20colorless%20reverberation).%20Original%20method%20published%20in%20*%22Differentiable%20Feedback%20Delay%20Network%20for%20Colorless%20Reverberation%2C%22%20G%20Dal%20Santo%2C%20K%20Prawda%2C%20SJ%20Schlecht%2C%20V%20V%C3%A4lim%C3%A4ki%2C%2026th%20International%20Conference%20on%20Digital%20Audio%20Effects%20(DAFx23)%2C%20244-251.*%0A%0A%20%20%20%20Parameters%20are%20loaded%20from%20%60.mat%60%20files%20(e.g.%20from%20%5Bdiff-fdn-colorless%5D(https%3A%2F%2Fgithub.com%2Fgdalsanto%2Fdiff-fdn-colorless)).%20The%20impulse%20response%20is%20computed%20with%20%60pyFDN.dss_to_impz%60.%20The%20modal%20decomposition%20(residue%20histogram)%20is%20omitted%20here%3A%20pyFDN%20provides%20it%20via%20%60pyFDN.dss_to_pr_direct%60%20%2F%20%60pyFDN.dss_to_pr_flamo%60%2C%20but%20for%20these%20FDNs%20it%20means%20solving%20for%20%60sum(delays)%60%20%E2%89%88%209000%20modes%2C%20which%20is%20too%20heavy%20for%20this%20quick%20example.%0A%0A%20%20%20%20-%20Original%20script%20in%20Matlab%3A%20Gloria%20Dal%20Santo%2C%20Wed%2C%2018.%20Oct%202023%0A%20%20%20%20-%20Python%20translation%3A%20Sebastian%20J.%20Schlecht%2C%202026-02-18%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%20from%20pathlib%20import%20Path%0A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20from%20scipy.io%20import%20loadmat%0A%20%20%20%20from%20scipy.linalg%20import%20expm%0A%0A%20%20%20%20import%20pyFDN%0A%0A%20%20%20%20return%20Path%2C%20expm%2C%20loadmat%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%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Path%2C%20pyFDN)%3A%0A%20%20%20%20fs%20%3D%2048000%0A%20%20%20%20rt%20%3D%203.0%0A%20%20%20%20ir_len%20%3D%20int(rt%20*%20fs)%0A%20%20%20%20g%20%3D%20pyFDN.db_to_lin(pyFDN.rt_to_slope(rt%2C%20fs))%0A%0A%20%20%20%20%23%20Resolve%20param_dir%3A%20nbsphinx%20runs%20with%20cwd%20%3D%20notebook%20dir%20(docs%2Fexamples%2F)%2C%20so%20go%20up%20to%20repo%20root%0A%20%20%20%20_param_candidates%20%3D%20%5B%0A%20%20%20%20%20%20%20%20Path.cwd().parent.parent%0A%20%20%20%20%20%20%20%20%2F%20%22examples%22%0A%20%20%20%20%20%20%20%20%2F%20%22resources%22%0A%20%20%20%20%20%20%20%20%2F%20%22colorless_FDN%22%2C%20%20%23%20from%20docs%2Fexamples%2F%0A%20%20%20%20%20%20%20%20Path.cwd().parent%20%2F%20%22examples%22%20%2F%20%22resources%22%20%2F%20%22colorless_FDN%22%2C%20%20%23%20from%20docs%2F%0A%20%20%20%20%20%20%20%20Path.cwd()%20%2F%20%22resources%22%20%2F%20%22colorless_FDN%22%2C%20%20%23%20from%20examples%2F%0A%20%20%20%20%20%20%20%20Path.cwd()%20%2F%20%22examples%22%20%2F%20%22resources%22%20%2F%20%22colorless_FDN%22%2C%20%20%23%20from%20project%20root%0A%20%20%20%20%5D%0A%20%20%20%20param_dir%20%3D%20next((p%20for%20p%20in%20_param_candidates%20if%20p.is_dir())%2C%20_param_candidates%5B0%5D)%0A%20%20%20%20return%20fs%2C%20g%2C%20ir_len%2C%20param_dir%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%20Choose%20parameter%20file%0A%0A%20%20%20%20Pick%20the%20FDN%20size%20%24N%24%20and%20delay%20set%3B%20the%20matching%20%60param_init_*%60%20file%20provides%20the%20random%20initialization.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo%2C%20param_dir)%3A%0A%20%20%20%20import%20re%0A%0A%20%20%20%20_pairs%20%3D%20sorted(%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20(int(match.group(1))%2C%20int(match.group(2)))%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20p%20in%20param_dir.glob(%22param_N*_d*.mat%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(match%20%3A%3D%20re.fullmatch(r%22param_N(%5Cd%2B)_d(%5Cd%2B)%5C.mat%22%2C%20p.name))%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20)%20or%20%5B(16%2C%201)%5D%0A%20%20%20%20_options%20%3D%20%7Bf%22N%20%3D%20%7Bn%7D%2C%20delay%20set%20%7Bd%7D%22%3A%20(n%2C%20d)%20for%20n%2C%20d%20in%20_pairs%7D%0A%20%20%20%20_default%20%3D%20%22N%20%3D%2016%2C%20delay%20set%201%22%0A%20%20%20%20param_choice%20%3D%20mo.ui.dropdown(%0A%20%20%20%20%20%20%20%20options%3D_options%2C%0A%20%20%20%20%20%20%20%20value%3D_default%20if%20_default%20in%20_options%20else%20next(iter(_options))%2C%0A%20%20%20%20%20%20%20%20label%3D%22Parameter%20file%22%2C%0A%20%20%20%20)%0A%20%20%20%20mo.vstack(%5Bparam_choice%5D)%0A%20%20%20%20return%20(param_choice%2C)%0A%0A%0A%40app.cell%0Adef%20_(param_choice)%3A%0A%20%20%20%20N%2C%20delay_set%20%3D%20param_choice.value%0A%20%20%20%20print(f%22Selected%3A%20N%3D%7BN%7D%2C%20delay%20set%20%7Bdelay_set%7D%22)%0A%20%20%20%20return%20N%2C%20delay_set%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%20Load%20parameters%20from%20mat%20file%0A%0A%20%20%20%20%60load_colorless_params(path%2C%20g)%60%20loads%20m%2C%20A%2C%20B%2C%20C%20from%20the%20mat%20file%2C%20builds%20Ag%20%3D%20expm(skew(A))%20%40%20diag(g%5Em)%20using%20%60pyFDN.skew%60%2C%20and%20returns%20(m_int%2C%20Ag%2C%20B%2C%20C%2C%20D)%20for%20use%20with%20dss2impz.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Path%2C%20expm%2C%20loadmat%2C%20np%2C%20pyFDN)%3A%0A%20%20%20%20def%20load_colorless_params(path)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Load%20colorless%20FDN%20parameters%20from%20a%20.mat%20file.%20Returns%20(m_int%2C%20A%2C%20B%2C%20C%2C%20D).%22%22%22%0A%20%20%20%20%20%20%20%20path%20%3D%20Path(path)%0A%20%20%20%20%20%20%20%20if%20not%20path.exists()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20raise%20FileNotFoundError(f%22Parameter%20file%20not%20found%3A%20%7Bpath%7D%22)%0A%20%20%20%20%20%20%20%20data%20%3D%20loadmat(path)%0A%20%20%20%20%20%20%20%20m%20%3D%20np.asarray(data%5B%22m%22%5D%2C%20dtype%3Dnp.float64).ravel()%0A%20%20%20%20%20%20%20%20A%20%3D%20np.asarray(data%5B%22A%22%5D%2C%20dtype%3Dnp.float64)%0A%20%20%20%20%20%20%20%20B%20%3D%20np.asarray(data%5B%22B%22%5D%2C%20dtype%3Dnp.float64).ravel().reshape(-1%2C%201)%0A%20%20%20%20%20%20%20%20C%20%3D%20np.asarray(data%5B%22C%22%5D%2C%20dtype%3Dnp.float64)%0A%20%20%20%20%20%20%20%20if%20C.ndim%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20C%20%3D%20C.reshape(1%2C%20-1)%0A%20%20%20%20%20%20%20%20D%20%3D%20np.zeros((1%2C%201))%0A%20%20%20%20%20%20%20%20A_skew%20%3D%20pyFDN.skew(A)%0A%20%20%20%20%20%20%20%20A%20%3D%20expm(A_skew)%0A%20%20%20%20%20%20%20%20m_int%20%3D%20np.round(m).astype(np.int64)%0A%20%20%20%20%20%20%20%20return%20m_int%2C%20A%2C%20B%2C%20C%2C%20D%0A%0A%20%20%20%20return%20(load_colorless_params%2C)%0A%0A%0A%40app.cell%0Adef%20_(N%2C%20delay_set%2C%20g%2C%20ir_len%2C%20load_colorless_params%2C%20np%2C%20param_dir%2C%20pyFDN)%3A%0A%20%20%20%20path_optim%20%3D%20param_dir%20%2F%20f%22param_N%7BN%7D_d%7Bdelay_set%7D.mat%22%0A%20%20%20%20m%2C%20A%2C%20B%2C%20C%2C%20D%20%3D%20load_colorless_params(path_optim)%0A%20%20%20%20_Gamma%20%3D%20np.diag(g**m)%0A%20%20%20%20Ag%20%3D%20A%20%40%20_Gamma%0A%20%20%20%20ir_optim%20%3D%20pyFDN.dss_to_impz(ir_len%2C%20m%2C%20Ag%2C%20B%2C%20C%2C%20D).squeeze()%0A%20%20%20%20return%20A%2C%20B%2C%20C%2C%20D%2C%20ir_optim%2C%20m%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%20Compare%20to%20initialization%20parameters%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(N%2C%20delay_set%2C%20g%2C%20ir_len%2C%20load_colorless_params%2C%20np%2C%20param_dir%2C%20pyFDN)%3A%0A%20%20%20%20path_init%20%3D%20param_dir%20%2F%20f%22param_init_N%7BN%7D_d%7Bdelay_set%7D.mat%22%0A%20%20%20%20m_i%2C%20A_i%2C%20B_i%2C%20C_i%2C%20D_i%20%3D%20load_colorless_params(path_init)%0A%20%20%20%20_Gamma%20%3D%20np.diag(g**m_i)%0A%20%20%20%20Ag_i%20%3D%20A_i%20%40%20_Gamma%0A%20%20%20%20ir_init%20%3D%20pyFDN.dss_to_impz(ir_len%2C%20m_i%2C%20Ag_i%2C%20B_i%2C%20C_i%2C%20D_i).squeeze()%0A%20%20%20%20return%20A_i%2C%20B_i%2C%20C_i%2C%20D_i%2C%20ir_init%2C%20m_i%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%20FDN%20parameter%20overview%0A%0A%20%20%20%20%60pyFDN.plot_fdn_parameter%60%20shows%20the%20system%20matrix%20blocks%20%24A%24%2C%20%24b%24%2C%20%24c%24%2C%20%24d%24%20as%20heatmaps%20and%20the%20delays%20as%20bars%20aligned%20with%20the%20columns%20of%20the%20feedback%20matrix.%20The%20optimization%20changes%20%24A%24%2C%20%24b%24%2C%20%24c%24%20(the%20lossless%20part%2C%20before%20the%20homogeneous%20attenuation%20%24%5CGamma%20%3D%20%5Cmathrm%7Bdiag%7D(g%5Em)%24%20is%20applied)%3B%20the%20delays%20stay%20fixed.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(A_i%2C%20B_i%2C%20C_i%2C%20D_i%2C%20m_i%2C%20pyFDN)%3A%0A%20%20%20%20pyFDN.plot_fdn_parameter(%0A%20%20%20%20%20%20%20%20m_i%2C%0A%20%20%20%20%20%20%20%20A_i%2C%0A%20%20%20%20%20%20%20%20B_i%2C%0A%20%20%20%20%20%20%20%20C_i%2C%0A%20%20%20%20%20%20%20%20D_i%2C%0A%20%20%20%20%20%20%20%20title%3D%22Random%20Initialization%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(A%2C%20B%2C%20C%2C%20D%2C%20m%2C%20pyFDN)%3A%0A%20%20%20%20pyFDN.plot_fdn_parameter(%0A%20%20%20%20%20%20%20%20m%2C%0A%20%20%20%20%20%20%20%20A%2C%0A%20%20%20%20%20%20%20%20B%2C%0A%20%20%20%20%20%20%20%20C%2C%0A%20%20%20%20%20%20%20%20D%2C%0A%20%20%20%20%20%20%20%20title%3D%22Optimized%22%2C%0A%20%20%20%20)%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%20Plot%20impulse%20responses%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(fs%2C%20ir_init%2C%20ir_optim%2C%20mo%2C%20np%2C%20pyFDN)%3A%0A%20%20%20%20plot%20%3D%20pyFDN.plot_impulse_response(%0A%20%20%20%20%20%20%20%20ir_optim%2C%0A%20%20%20%20%20%20%20%20ir_init%2C%0A%20%20%20%20%20%20%20%20fs%3Dfs%2C%0A%20%20%20%20%20%20%20%20labels%3D%5B%22Optimized%22%2C%20%22Random%20Initialization%22%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20audio_blocks%20%3D%20mo.vstack(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.Html(%22Random%20Initialization%22).style(%7B%22font-size%22%3A%20%222.0em%22%7D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.audio(np.asarray(ir_init)%2C%20rate%3Dfs)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.Html(%22Optimized%22).style(%7B%22font-size%22%3A%20%222.0em%22%7D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20mo.audio(np.asarray(ir_optim)%2C%20rate%3Dfs)%2C%0A%20%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%20gap%3D1%2C%0A%20%20%20%20)%0A%20%20%20%20mo.vstack(%5Bplot%2C%20audio_blocks%5D%2C%20gap%3D3)%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
405f891dedf296a10b05707c5664274d