%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%20eigenvectors%20(mode%20shapes)%0A%0A%20%20%20%20Demonstrates%20how%20to%20compute%20the%20mode%20shapes%20of%20an%20FDN%20from%20the%20left%20and%0A%20%20%20%20right%20eigenvectors%20of%20the%20loop%20polynomial%20%24P(z)%20%3D%20D_m(z)%20-%20A%24.%0A%0A%20%20%20%20Each%20residue%20factors%20into%20the%20input%2Foutput%20drive%20and%20an%20undriven%20part%3A%0A%0A%20%20%20%20%24%24%5Crho_i%20%3D%20%5Cfrac%7B(c%5C%2C%20r_i)%5C%2C(l_i%5EH%20b)%7D%7Bl_i%5EH%20P'(%5Clambda_i)%5C%2C%20r_i%7D%2C%24%24%0A%0A%20%20%20%20where%20%24r_i%24%20and%20%24l_i%24%20are%20the%20right%2Fleft%20null%20vectors%20of%20%24P(%5Clambda_i)%24.%0A%20%20%20%20The%20eigenvectors%20live%20on%20the%20delay%20lines%3B%20expanding%20each%20entry%20along%20its%0A%20%20%20%20delay%20line%20with%20%24%5Clambda_i%5Ek%24%20gives%20the%20mode%20shape%20over%20the%20full%20state.%0A%0A%20%20%20%20Reference%3A%20*Schlecht%20et%20al.%20(2024).%20Modal%20Excitation%20in%20Feedback%20Delay%0A%20%20%20%20Networks.*%0A%0A%20%20%20%20Original%20MATLAB%3A%20%60example_FDNEigenvectors.m%60%2C%20Sebastian%20J.%20Schlecht%2C%0A%20%20%20%2027%20February%202024.%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.graph_objects%20as%20go%0A%20%20%20%20import%20plotly.io%20as%20pio%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%20go%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%20Define%20FDN%20and%20modal%20decomposition%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(1)%0A%20%20%20%20delays%20%3D%20np.array(%5B13%2C%2019%2C%2023%5D)%0A%20%20%20%20build%20%3D%20pyFDN.fdn_build_gallery(%0A%20%20%20%20%20%20%20%20delays%3Ddelays%2C%0A%20%20%20%20%20%20%20%20io_type%3D%22ones%22%2C%0A%20%20%20%20%20%20%20%20direct_gain%3D0.0%2C%0A%20%20%20%20%20%20%20%20rt%3DNone%2C%0A%20%20%20%20%20%20%20%20rng%3D1%2C%0A%20%20%20%20)%0A%20%20%20%20%23%20Bake%20delay-proportional%20broadband%20decay%20into%20the%20lossless%20feedback%20matrix.%0A%20%20%20%20delays%20%3D%20build.delays%0A%20%20%20%20A%20%3D%20np.diag(0.98**delays)%20%40%20build.A%0A%20%20%20%20b%2C%20c%2C%20d%20%3D%20build.B%2C%20build.C%2C%20build.D%0A%20%20%20%20num_delays%20%3D%20delays.size%0A%20%20%20%20return%20A%2C%20b%2C%20c%2C%20d%2C%20delays%2C%20num_delays%0A%0A%0A%40app.cell%0Adef%20_(A%2C%20b%2C%20c%2C%20d%2C%20delays%2C%20pyFDN)%3A%0A%20%20%20%20residues%2C%20poles%2C%20direct%2C%20is_pair%2C%20meta%20%3D%20pyFDN.dss_to_pr(delays%2C%20A%2C%20b%2C%20c%2C%20d)%0A%20%20%20%20num_modes%20%3D%20poles.size%0A%20%20%20%20rv%20%3D%20meta%5B%22eigenvectors%22%5D%5B%22right%22%5D%20%20%23%20(N%2C%20num_modes)%0A%20%20%20%20lv%20%3D%20meta%5B%22eigenvectors%22%5D%5B%22left%22%5D%0A%20%20%20%20undriven%20%3D%20meta%5B%22undrivenResidues%22%5D%0A%20%20%20%20print(f%22Number%20of%20modes%20(conjugate%20pairs%20reduced)%3A%20%7Bnum_modes%7D%22)%0A%20%20%20%20return%20direct%2C%20is_pair%2C%20lv%2C%20num_modes%2C%20poles%2C%20residues%2C%20rv%2C%20undriven%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%20Residues%20from%20eigenvectors%0A%0A%20%20%20%20Reassemble%20the%20residues%20from%20the%20eigenvectors%20and%20the%20undriven%20part%3B%20the%0A%20%20%20%20result%20matches%20the%20residues%20returned%20by%20the%20modal%20decomposition.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(b%2C%20c%2C%20lv%2C%20np%2C%20residues%2C%20rv%2C%20undriven)%3A%0A%20%20%20%20res_compact%20%3D%20undriven%20*%20(c%20%40%20rv).ravel()%20*%20(lv.conj().T%20%40%20b).ravel()%0A%20%20%20%20max_residue_error%20%3D%20np.max(np.abs(residues%5B%3A%2C%200%2C%200%5D%20-%20res_compact))%0A%20%20%20%20print(f%22Max%20%7Cresidue%20-%20compact%20residue%7C%20%3D%20%7Bmax_residue_error%3A.3e%7D%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%20Impulse%20response%20check%0A%0A%20%20%20%20Compare%20the%20time-domain%20recursion%20with%20the%20modal%20synthesis.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(A%2C%20b%2C%20c%2C%20d%2C%20delays%2C%20direct%2C%20go%2C%20is_pair%2C%20np%2C%20poles%2C%20pyFDN%2C%20residues)%3A%0A%20%20%20%20ir_len%20%3D%201000%0A%20%20%20%20ir_time%20%3D%20pyFDN.dss_to_impz(ir_len%2C%20delays%2C%20A%2C%20b%2C%20c%2C%20d)%5B%3A%2C%200%2C%200%5D%0A%20%20%20%20ir_modal%20%3D%20pyFDN.pr_to_impz(residues%2C%20poles%2C%20direct%2C%20is_pair%2C%20ir_len)%5B%3A%2C%200%2C%200%5D%0A%0A%20%20%20%20fig_ir%20%3D%20go.Figure()%0A%20%20%20%20fig_ir.add_trace(%0A%20%20%20%20%20%20%20%20go.Scatter(y%3Dir_time%2C%20mode%3D%22lines%22%2C%20name%3D%22Impulse%20response%20(time%20domain)%22)%0A%20%20%20%20)%0A%20%20%20%20fig_ir.add_trace(%0A%20%20%20%20%20%20%20%20go.Scatter(y%3Dir_modal%20%2B%201.0%2C%20mode%3D%22lines%22%2C%20name%3D%22IR%20pole%20residue%20(%2B1%20offset)%22)%0A%20%20%20%20)%0A%20%20%20%20fig_ir.update_layout(%0A%20%20%20%20%20%20%20%20title%3Df%22Time%20domain%20vs%20modal%20synthesis%20(max%20err%20%3D%20%7Bnp.max(np.abs(ir_time%20-%20ir_modal))%3A.2e%7D)%22%2C%0A%20%20%20%20%20%20%20%20xaxis%3D%7B%22title%22%3A%20%22Time%20(samples)%22%7D%2C%0A%20%20%20%20%20%20%20%20yaxis%3D%7B%22title%22%3A%20%22Impulse%20response%20value%22%7D%2C%0A%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20height%3D400%2C%0A%20%20%20%20)%0A%20%20%20%20fig_ir.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%20Mode%20shapes%20over%20the%20full%20state%20space%0A%0A%20%20%20%20Expand%20the%20eigenvectors%20along%20each%20delay%20line%3A%20state%20%24k%24%20of%20delay%20line%20%24j%24%0A%20%20%20%20carries%20%24r_%7Bj%2Ci%7D%5C%2C%5Clambda_i%5Ek%24.%20Horizontal%20lines%20mark%20the%20delay-line%0A%20%20%20%20boundaries.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(delays%2C%20go%2C%20np%2C%20num_delays%2C%20num_modes%2C%20poles%2C%20rv)%3A%0A%20%20%20%20rv_state_blocks%20%3D%20%5B%5D%0A%20%20%20%20for%20_j%20in%20range(num_delays)%3A%0A%20%20%20%20%20%20%20%20_powers%20%3D%20poles%5BNone%2C%20%3A%5D%20**%20np.arange(delays%5B_j%5D)%5B%3A%2C%20None%5D%0A%20%20%20%20%20%20%20%20rv_state_blocks.append(rv%5B_j%2C%20%3A%5D%5BNone%2C%20%3A%5D%20*%20_powers)%0A%20%20%20%20rv_state%20%3D%20np.vstack(rv_state_blocks)%20%20%23%20(sum(delays)%2C%20num_modes)%0A%0A%20%20%20%20fig_state%20%3D%20go.Figure(%0A%20%20%20%20%20%20%20%20go.Heatmap(%0A%20%20%20%20%20%20%20%20%20%20%20%20z%3Dnp.real(rv_state)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colorscale%3D%22RdBu%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20zmid%3D0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colorbar%3D%7B%22title%22%3A%20%22Re%22%7D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20for%20_boundary%20in%20np.cumsum(delays)%5B%3A-1%5D%3A%0A%20%20%20%20%20%20%20%20fig_state.add_hline(y%3D_boundary%20-%200.5%2C%20line%3D%7B%22color%22%3A%20%22black%22%2C%20%22width%22%3A%202%7D)%0A%20%20%20%20fig_state.update_layout(%0A%20%20%20%20%20%20%20%20title%3D%22Right%20eigenvectors%20expanded%20over%20the%20state%20space%22%2C%0A%20%20%20%20%20%20%20%20xaxis%3D%7B%22title%22%3A%20%22Eigenvalue%20index%20i%22%2C%20%22range%22%3A%20%5B-0.5%2C%20num_modes%20-%200.5%5D%7D%2C%0A%20%20%20%20%20%20%20%20yaxis%3D%7B%22title%22%3A%20%22State%20space%20index%22%2C%20%22autorange%22%3A%20%22reversed%22%7D%2C%0A%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20height%3D520%2C%0A%20%20%20%20)%0A%20%20%20%20fig_state.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%20Right%20eigenvectors%20on%20the%20delay%20lines%0A%0A%20%20%20%20The%20raw%20right%20eigenvectors%2C%20one%20row%20per%20delay%20line.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(go%2C%20np%2C%20num_modes%2C%20rv)%3A%0A%20%20%20%20fig_rv%20%3D%20go.Figure(%0A%20%20%20%20%20%20%20%20go.Heatmap(%0A%20%20%20%20%20%20%20%20%20%20%20%20z%3Dnp.real(rv)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colorscale%3D%22RdBu%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20zmid%3D0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20colorbar%3D%7B%22title%22%3A%20%22Re%22%2C%20%22orientation%22%3A%20%22h%22%7D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20fig_rv.update_layout(%0A%20%20%20%20%20%20%20%20title%3D%22Right%20eigenvectors%20(per%20delay%20line)%22%2C%0A%20%20%20%20%20%20%20%20xaxis%3D%7B%22title%22%3A%20%22Eigenvalue%20index%20i%22%2C%20%22range%22%3A%20%5B-0.5%2C%20num_modes%20-%200.5%5D%7D%2C%0A%20%20%20%20%20%20%20%20yaxis%3D%7B%22title%22%3A%20%22Delay%20index%22%2C%20%22autorange%22%3A%20%22reversed%22%7D%2C%0A%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20height%3D300%2C%0A%20%20%20%20)%0A%20%20%20%20fig_rv.show()%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
fbff39e1a764d25db061ffae35ecdf6b