%23%20gallery_category%3A%20Special%20FDNs%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%20Scattering%20Delay%20Network%20(SDN)%20Demo%0A%0A%20%20%20%20This%20example%20uses%20the%20**Scattering%20Delay%20Network%20(SDN)**%20to%20compute%20room%20acoustics%20coefficients%20(delays%2C%20feedback%20matrix%2C%20wall%20filters)%20from%20geometry%20and%20wall%20absorption%2C%20then%20builds%20a%20**FLAMO**%20model%20to%20render%20the%20impulse%20response.%0A%0A%20%20%20%20**Pipeline%3A**%20SDN%20(room%2C%20source%2Freceiver%2C%20wall%20filters)%20%E2%86%92%20%60sdn.compute()%60%20%E2%86%92%20%60sdn.sdn_to_flamo(nfft)%60%20%E2%86%92%20FLAMO%20model%20%E2%86%92%20%60pyFDN.flamo_time_response()%60%20%E2%86%92%20NumPy%20IR.%0A%0A%20%20%20%20Original%20code%20of%20SDN%3A%20Enzo%20de%20Sena%2C%20Orchisama%20Das%0A%20%20%20%20Python%20Translation%3A%20Sebastian%20J.%20Schlecht%2C%20Friday%2C%2020.%20February%202026%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%20%20%20%20from%20scipy.linalg%20import%20block_diag%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%0A%20%20%20%20import%20pyFDN%0A%0A%20%20%20%20return%20block_diag%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%20Room%20and%20wall%20filters%0A%0A%20%20%20%20Define%20room%20size%2C%20source%20and%20receiver%20positions%2C%20and%20sample%20rate.%20Wall%20filters%20are%20first-order%20shelving%20EQs%20in%20second-order-section%20(SOS)%20format%2C%20with%20separate%20gains%20at%20DC%20and%20Nyquist.%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%20room_size%20%3D%20np.array(%5B7%2C%209%2C%205%5D)%0A%20%20%20%20source_pos%20%3D%20np.array(%5B0.3%2C%200.5%2C%200.9%5D)%20*%20room_size%0A%20%20%20%20receiver_pos%20%3D%20np.array(%5B0.4%2C%200.1%2C%200.4%5D)%20*%20room_size%0A%20%20%20%20Fs%20%3D%2044100%0A%0A%20%20%20%20%23%20Wall%20filters%3A%20one%20first-order%20shelving%20EQ%20per%20wall%2C%20shared%20by%20its%205%20outputs.%0A%20%20%20%20wall_sos%20%3D%20pyFDN.first_order_shelving_eq(%0A%20%20%20%20%20%20%20%20db_dc%3Dnp.full(6%2C%20-1.0)%2C%0A%20%20%20%20%20%20%20%20db_nyquist%3Dnp.full(6%2C%20-6.0)%2C%0A%20%20%20%20%20%20%20%20fs%3DFs%2C%0A%20%20%20%20%20%20%20%20crossover_frequency%3D8000.0%2C%0A%20%20%20%20)%0A%20%20%20%20wall_filters%20%3D%20%5B%5Bwall_sos%5B%3A%2C%20%3A%2C%20wall%5D%20for%20_%20in%20range(5)%5D%20for%20wall%20in%20range(6)%5D%0A%20%20%20%20return%20Fs%2C%20receiver_pos%2C%20room_size%2C%20source_pos%2C%20wall_filters%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%20SDN%20compute%0A%0A%20%20%20%20Build%20the%20SDN%20and%20run%20%60compute()%60%20to%20get%20delays%2C%20routing%2C%20scattering%2C%20and%20wall%20filter%20coefficients.%20No%20time-domain%20simulation%20is%20run%20here%E2%80%94only%20coefficient%20extraction.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Fs%2C%20pyFDN%2C%20receiver_pos%2C%20room_size%2C%20source_pos%2C%20wall_filters)%3A%0A%20%20%20%20sdn%20%3D%20pyFDN.SDN(%0A%20%20%20%20%20%20%20%20room_size%3Droom_size%2C%0A%20%20%20%20%20%20%20%20source_pos%3Dsource_pos%2C%0A%20%20%20%20%20%20%20%20receiver_pos%3Dreceiver_pos%2C%0A%20%20%20%20%20%20%20%20Fs%3DFs%2C%0A%20%20%20%20%20%20%20%20wall_filters%3Dwall_filters%2C%0A%20%20%20%20)%0A%20%20%20%20_%20%3D%20sdn.compute()%20%20%23%20mutates%20sdn%20in%20place%3B%20assign%20to%20suppress%20the%20result-dict%20output%0A%20%20%20%20return%20(sdn%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%203D%20visualization%0A%0A%20%20%20%20Optional%3A%20visualize%20the%20room%2C%20source%2C%20and%20receiver.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(sdn)%3A%0A%20%20%20%20sdn.visualize(show%3DFalse)%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%20FLAMO%20model%20and%20impulse%20response%0A%0A%20%20%20%20Convert%20the%20SDN%20result%20into%20a%20FLAMO%20model%20(feedback%20delays%2C%20feedback%20matrix%2C%20absorption%20filters).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(sdn)%3A%0A%20%20%20%20nfft%20%3D%202**17%0A%20%20%20%20model%2C%20sdn_result%20%3D%20sdn.sdn_to_flamo(nfft%3Dnfft)%0A%20%20%20%20return%20model%2C%20sdn_result%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%20signal-flow%20graph%0A%0A%20%20%20%20The%20SDN%20is%20a%2030-line%20FDN%20with%20input%2Foutput%20routing.%20%60pyFDN.plot_flamo_graph%60%20draws%20the%20full%20FLAMO%20signal%20flow%3A%20source%E2%86%92wall%20input%20path%2C%20the%20scattering%2Fpermutation%20feedback%20loop%20with%20wall%20filters%2C%20the%20wall%E2%86%92receiver%20output%20path%2C%20and%20the%20parallel%20direct%20path.%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%20Plot%20impulse%20response%0A%20%20%20%20Obtain%20the%20impulse%20response%20as%20a%20NumPy%20array%20via%20%60pyFDN.flamo_time_response()%60.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Fs%2C%20mo%2C%20model%2C%20pyFDN)%3A%0A%20%20%20%20ir%20%3D%20pyFDN.flamo_time_response(model).squeeze()%0A%20%20%20%20fig%20%3D%20pyFDN.plot_impulse_response(%0A%20%20%20%20%20%20%20%20ir%2C%0A%20%20%20%20%20%20%20%20fs%3DFs%2C%0A%20%20%20%20%20%20%20%20mulaw%3DFalse%2C%0A%20%20%20%20%20%20%20%20title%3D%22SDN%20impulse%20response%20(FLAMO)%22%2C%0A%20%20%20%20)%0A%20%20%20%20mo.vstack(%5Bfig%2C%20mo.audio(ir%2C%20Fs)%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%20FDN%20parameter%20overview%0A%0A%20%20%20%20The%20core%20feedback%20loop%20reconstructed%20as%20standard%20FDN%20parameters%3A%20feedback%20matrix%20%60A%20%3D%20blockdiag(scattering)%20%40%20permutation%60%2C%20net%20per-line%20input%2Foutput%20gains%2C%20the%20direct-path%20gain%2C%20and%20the%20wall%20filters%20as%20the%20per-line%20attenuation.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(block_diag%2C%20np%2C%20pyFDN%2C%20sdn_result)%3A%0A%20%20%20%20A%20%3D%20(%0A%20%20%20%20%20%20%20%20block_diag(*sdn_result%5B%22scattering_matrices%22%5D)%0A%20%20%20%20%20%20%20%20%40%20sdn_result%5B%22permutation_matrix%22%5D%0A%20%20%20%20)%0A%20%20%20%20delays_smp%20%3D%20np.rint(%0A%20%20%20%20%20%20%20%20np.asarray(sdn_result%5B%22delay_lengths_flat%22%5D)%20*%20sdn_result%5B%22Fs%22%5D%0A%20%20%20%20).astype(int)%0A%20%20%20%20B%20%3D%20sdn_result%5B%22input_matrix%22%5D%20%40%20np.asarray(sdn_result%5B%22input_gains%22%5D).reshape(%0A%20%20%20%20%20%20%20%20-1%2C%201%0A%20%20%20%20)%0A%20%20%20%20C%20%3D%20(%0A%20%20%20%20%20%20%20%20np.asarray(sdn_result%5B%22output_gains%22%5D).reshape(1%2C%20-1)%0A%20%20%20%20%20%20%20%20%40%20sdn_result%5B%22output_matrix%22%5D%0A%20%20%20%20)%0A%20%20%20%20D%20%3D%20np.array(%5B%5Bsdn_result%5B%22direct_path_gain%22%5D%5D%5D)%0A%0A%20%20%20%20pyFDN.plot_fdn_parameter(%0A%20%20%20%20%20%20%20%20delays_smp%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%20attenuation_sos%3Dsdn_result%5B%22wall_filters_sos%22%5D%2C%0A%20%20%20%20%20%20%20%20fs%3Dsdn_result%5B%22Fs%22%5D%2C%0A%20%20%20%20%20%20%20%20title%3D%22SDN%20FDN%20parameters%22%2C%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
2ffbea7e5fb8e3a97e44dd16f26e457a