%23%20gallery_category%3A%20Representations%0A%23%20gallery_description%3A%20Convert%20a%20delay%20state-space%20FDN%20into%20a%20matrix%20transfer%20function%20and%20verify%20the%20result%20in%20the%20time%20domain.%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.24.0%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%20Delay%20state-space%20to%20transfer%20function%0A%0A%20%20%20%20An%20FDN%20in%20delay%20state-space%20form%20keeps%20the%20delays%20separate%20from%20the%20feedback%20matrix.%20%60dss_to_tf%60%20collapses%20that%20structure%20into%20a%20matrix%20transfer%20function%3A%20a%20shared%20denominator%20polynomial%20%60tfA%60%20%E2%80%94%20the%20loop's%20characteristic%20polynomial%20%E2%80%94%20and%20a%20numerator%20polynomial%20%60tfB%60%20per%20input%2Foutput%20pair.%0A%0A%20%20%20%20The%20two%20forms%20describe%20the%20same%20system%2C%20so%20they%20must%20produce%20the%20same%20impulse%20response.%20Rendering%20the%20delay%20recursion%20directly%20(%60dss_to_impz%60)%20and%20evaluating%20the%20polynomials%20(%60mtf_to_impz%60)%20is%20the%20check%2C%20and%20it%20is%20exact%20to%20machine%20precision%20because%20no%20approximation%20is%20involved%20%E2%80%94%20only%20a%20change%20of%20representation.%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%20A%20MIMO%20FDN%0A%0A%20%20%20%20Four%20delay%20lines%20with%20a%20random%20orthogonal%20feedback%20matrix%2C%20three%20inputs%20and%20two%20outputs%2C%20so%20the%20transfer%20function%20is%20a%202x3%20matrix%20of%20polynomials%20over%20one%20common%20denominator.%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%0A%20%20%20%20import%20pyFDN%0A%0A%20%20%20%20np.random.seed(5)%0A%20%20%20%20fs%20%3D%2048000%0A%20%20%20%20impulse_response_length%20%3D%20fs%20%2F%2F%20100%0A%0A%20%20%20%20build%20%3D%20pyFDN.fdn_build_gallery(%0A%20%20%20%20%20%20%20%204%2C%0A%20%20%20%20%20%20%20%20fs%3Dfs%2C%0A%20%20%20%20%20%20%20%20delay_range%3D(50%2C%20101)%2C%0A%20%20%20%20%20%20%20%20num_inputs%3D3%2C%0A%20%20%20%20%20%20%20%20num_outputs%3D2%2C%0A%20%20%20%20%20%20%20%20io_type%3D%22identity%22%2C%0A%20%20%20%20%20%20%20%20direct_gain%3DNone%2C%0A%20%20%20%20%20%20%20%20rt%3DNone%2C%0A%20%20%20%20%20%20%20%20rng%3D5%2C%0A%20%20%20%20)%0A%20%20%20%20A%2C%20B%2C%20C%2C%20D%2C%20delays%20%3D%20(%0A%20%20%20%20%20%20%20%20build.A%2C%0A%20%20%20%20%20%20%20%20build.B%2C%0A%20%20%20%20%20%20%20%20build.C%2C%0A%20%20%20%20%20%20%20%20build.D%2C%0A%20%20%20%20%20%20%20%20build.delays%2C%0A%20%20%20%20)%0A%20%20%20%20return%20A%2C%20B%2C%20C%2C%20D%2C%20delays%2C%20impulse_response_length%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%20Through%20the%20transfer%20function%0A%0A%20%20%20%20%60dss_to_tf%60%20returns%20%60(tfB%2C%20tfA)%60%20in%20ascending%20powers%20of%20%24z%5E%7B-1%7D%24%3B%20%60mtf_to_impz%60%20runs%20the%20resulting%20polynomial%20ratio%20out%20to%20%60impulse_response_length%60%20samples.%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%20impulse_response_length%2C%20pyFDN)%3A%0A%20%20%20%20tfB%2C%20tfA%20%3D%20pyFDN.dss_to_tf(delays%2C%20A%2C%20B%2C%20C%2C%20D)%0A%20%20%20%20ir_tf%20%3D%20pyFDN.mtf_to_impz(tfB%2C%20tfA%2C%20impulse_response_length)%0A%20%20%20%20return%20(ir_tf%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%20Through%20the%20delay%20recursion%0A%0A%20%20%20%20The%20same%20system%20run%20as%20a%20time-domain%20recursion%20over%20the%20delay%20lines%2C%20which%20is%20the%20reference%20the%20transfer%20function%20has%20to%20reproduce.%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%20impulse_response_length%2C%20pyFDN)%3A%0A%20%20%20%20ir_dss%20%3D%20pyFDN.dss_to_impz(impulse_response_length%2C%20delays%2C%20A%2C%20B%2C%20C%2C%20D)%0A%20%20%20%20return%20(ir_dss%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%20Both%20impulse%20response%20matrices%0A%0A%20%20%20%20One%20panel%20per%20input%2Foutput%20pair%2C%20transfer%20function%20above%20and%20delay%20recursion%20below.%20The%20two%20grids%20are%20indistinguishable.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ir_dss%2C%20ir_tf%2C%20mo%2C%20pyFDN)%3A%0A%20%20%20%20fig1%20%3D%20pyFDN.plot_impulse_response_matrix(t%3DNone%2C%20ir%3Dir_tf)%0A%20%20%20%20fig2%20%3D%20pyFDN.plot_impulse_response_matrix(t%3DNone%2C%20ir%3Dir_dss)%0A%0A%20%20%20%20mo.vstack(%5Bfig1%2C%20fig2%5D)%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%20Verification%0A%0A%20%20%20%20Indistinguishable%20by%20eye%20is%20not%20a%20check%3B%20this%20one%20is%20to%20%2410%5E%7B-10%7D%24.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(ir_dss%2C%20ir_tf%2C%20pyFDN)%3A%0A%20%20%20%20assert%20pyFDN.is_almost_zero(ir_dss%20-%20ir_tf%2C%20tol%3D1e-10)%2C%20(%0A%20%20%20%20%20%20%20%20%22IR%20from%20TF%20and%20DSS%20should%20match%22%0A%20%20%20%20)%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
65100ec2ea59e108f0f1a2954889c45e