%23%20gallery_category%3A%20Analysis%20%26%20Verification%0A%23%20gallery_description%3A%20Measure%20how%20a%20velvet-noise%20scattering%20feedback%20matrix%20decorrelates%20the%20input-output%20paths%20of%20an%20FDN.%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%20Decorrelation%20in%20feedback%20delay%20networks%0A%0A%20%20%20%20Analyses%20the%20decorrelation%20properties%20of%20an%20FDN%20with%20a%20velvet-noise%20scattering%20feedback%20matrix.%0A%0A%20%20%20%20The%20MIMO%20transfer%20function%20of%20an%20FDN%20factorises%20as%20%24H(z)%20%3D%20C%20%5C%2C%20%5Cmathrm%7Badj%7D(P(z))%20B%20%5C%2C%2F%5C%2C%20%5Cdet(P(z))%20%2B%20D%24%20with%20the%20characteristic%20matrix%20%24P(z)%20%3D%20%5Cmathrm%7Bdiag%7D(z%5E%7Bm%7D)%20-%20A(z)%24.%20%20The%20adjugate%20matrix%20%24%5Cmathrm%7Badj%7D(P(z))%24%20collects%20the%20FIR%20filters%20that%20differentiate%20the%20input-output%20paths%3A%20the%20more%20decorrelated%20its%20entries%2C%20the%20more%20decorrelated%20the%20FDN%20outputs.%20%20Here%20we%20compute%20the%20adjugate%2C%20then%20the%20pairwise%20maximum%20cross-correlation%20between%20all%20of%20its%20entries.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo%2C%20pyFDN)%3A%0A%20%20%20%20mo.md(f%22%22%22%0A%20%20%20%20Reference%3A%20*%7BpyFDN.paper_link(%22Decorrelation_in_Feedback_Delay_Networks%22)%7D*%0A%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%0A%20%20%20%20import%20pyFDN%0A%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%0A%0A%20%20%20%20A%20small%20FDN%20(%24N%20%3D%204%24)%20with%20random%20delays%20and%20a%20sparse%20velvet-noise%20paraunitary%20feedback%20matrix%20(3%20cascaded%20stages%2C%20sparsity%203).%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(5)%0A%0A%20%20%20%20num_delays%20%3D%204%0A%20%20%20%20delays%20%3D%20np.random.randint(300%2C%201001%2C%20num_delays)%0A%0A%20%20%20%20num_stages%20%3D%203%0A%20%20%20%20sparsity%20%3D%203%0A%20%20%20%20feedback_matrix%2C%20_%20%3D%20pyFDN.construct_velvet_feedback_matrix(%0A%20%20%20%20%20%20%20%20num_delays%2C%20num_stages%2C%20sparsity%0A%20%20%20%20)%0A%0A%20%20%20%20print(f%22Delays%3A%20%7Bdelays%7D%22)%0A%20%20%20%20print(f%22Feedback%20matrix%3A%20%7Bfeedback_matrix.shape%5B2%5D%7D%20taps%22)%0A%20%20%20%20return%20delays%2C%20feedback_matrix%2C%20num_delays%0A%0A%0A%40app.cell%0Adef%20_(go%2C%20np)%3A%0A%20%20%20%20def%20summarise_correlation(matrix)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Median%20and%20IQR%20of%20the%20off-diagonal%20maximum%20correlations.%22%22%22%0A%20%20%20%20%20%20%20%20upper%20%3D%20np.abs(matrix%5Bnp.triu_indices(matrix.shape%5B0%5D%2C%20k%3D1)%5D)%0A%20%20%20%20%20%20%20%20values%20%3D%20upper%5Bupper%20%3E%3D%20np.finfo(float).eps%5D%0A%20%20%20%20%20%20%20%20iqr%20%3D%20np.percentile(values%2C%2075)%20-%20np.percentile(values%2C%2025)%0A%20%20%20%20%20%20%20%20return%20np.median(values)%2C%20iqr%0A%0A%20%20%20%20def%20correlation_heatmap(matrix%2C%20labels%2C%20title%2C%20axis_titles%2C%20size)%3A%0A%20%20%20%20%20%20%20%20fig%20%3D%20go.Figure(%0A%20%20%20%20%20%20%20%20%20%20%20%20go.Heatmap(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20z%3Dnp.abs(matrix)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20x%3Dlabels%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20y%3Dlabels%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20zmin%3D0%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20zmax%3D1%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20colorscale%3D%22gray%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20colorbar%3D%7B%22title%22%3A%20%22%7Cmax%20corr%7C%22%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20fig.update_layout(%0A%20%20%20%20%20%20%20%20%20%20%20%20title%3Dtitle%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20xaxis%3D%7B%22title%22%3A%20axis_titles%5B0%5D%2C%20%22type%22%3A%20%22category%22%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20yaxis%3D%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22title%22%3A%20axis_titles%5B1%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22type%22%3A%20%22category%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22autorange%22%3A%20%22reversed%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20template%3D%22plotly_white%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20height%3Dsize%5B0%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20width%3Dsize%5B1%5D%2C%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%20return%20fig%0A%0A%20%20%20%20return%20correlation_heatmap%2C%20summarise_correlation%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%20Adjugate%20of%20the%20characteristic%20matrix%0A%0A%20%20%20%20%60loop_tf%60%20constructs%20the%20polynomial%20matrix%20%24P(z)%24%3B%20%60adj_poly%60%20computes%20its%20adjugate%20by%20evaluating%20%24P%24%20on%20a%20DFT%20grid%2C%20taking%20the%20scalar%20adjugate%20at%20every%20bin%2C%20and%20transforming%20back.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(delays%2C%20feedback_matrix%2C%20pyFDN)%3A%0A%20%20%20%20P%20%3D%20pyFDN.loop_tf(delays%2C%20feedback_matrix)%0A%20%20%20%20adj_mat%20%3D%20pyFDN.adj_poly(P%2C%20%22z%5E1%22)%0A%20%20%20%20print(f%22Loop%20transfer%20function%20P%3A%20%7BP.shape%7D%22)%0A%20%20%20%20print(f%22Adjugate%20matrix%3A%20%7Badj_mat.shape%7D%22)%0A%20%20%20%20return%20P%2C%20adj_mat%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%20matrix%0A%0A%20%20%20%20Each%20subplot%20is%20one%20FIR%20entry%20of%0A%20%20%20%20-%20%24P(z)%24%20-%20characteristic%20matrix%0A%20%20%20%20-%20%24%5Cmathrm%7Badj%7D(P(z))%24%20%E2%80%94%20the%20path%20filter%20from%20delay-line%20input%20%24j%24%20to%20delay-line%20output%20%24i%24%20(up%20to%20the%20common%20denominator%20%24%5Cdet%20P(z)%24).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(P%2C%20adj_mat%2C%20mo%2C%20pyFDN)%3A%0A%20%20%20%20_fig_char%2C%20_%2C%20_%20%3D%20pyFDN.plot_impulse_response_matrix(%0A%20%20%20%20%20%20%20%20None%2C%0A%20%20%20%20%20%20%20%20P.transpose(2%2C%200%2C%201)%2C%0A%20%20%20%20%20%20%20%20xlabel%3D%22Time%20(samples)%22%2C%0A%20%20%20%20%20%20%20%20ylabel%3D%22Sample%20value%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Characteristic%20matrix%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D0.6%2C%0A%20%20%20%20)%0A%20%20%20%20_fig_adj%2C%20_%2C%20_%20%3D%20pyFDN.plot_impulse_response_matrix(%0A%20%20%20%20%20%20%20%20None%2C%0A%20%20%20%20%20%20%20%20adj_mat.transpose(2%2C%200%2C%201)%2C%0A%20%20%20%20%20%20%20%20xlabel%3D%22Time%20(samples)%22%2C%0A%20%20%20%20%20%20%20%20ylabel%3D%22Sample%20value%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Adjugate%20of%20the%20characteristic%20matrix%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D0.6%2C%0A%20%20%20%20)%0A%0A%20%20%20%20mo.vstack(%5B_fig_char%2C%20_fig_adj%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%20Correlation%20analysis%0A%0A%20%20%20%20%60max_corr%60%20computes%20the%20maximum%20normalized%20cross-correlation%20over%20all%20lags%20between%20every%20pair%20of%20adjugate%20entries%20(16%20signals%20for%20%24N%20%3D%204%24%2C%20i.e.%20a%20%2416%20%5Ctimes%2016%24%20matrix).%20%20The%20median%20and%20interquartile%20range%20of%20the%20off-diagonal%20correlations%20summarise%20how%20decorrelated%20the%20paths%20are.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(adj_mat%2C%20pyFDN%2C%20summarise_correlation)%3A%0A%20%20%20%20max_correlation%20%3D%20pyFDN.max_corr(adj_mat)%0A%0A%20%20%20%20_median%2C%20_iqr%20%3D%20summarise_correlation(max_correlation)%0A%20%20%20%20print(f%22Median%20correlation%20metric%3A%20%7B_median%3A.4f%7D%22)%0A%20%20%20%20print(f%22Interquartile%20range%3A%20%20%20%20%20%20%20%7B_iqr%3A.4f%7D%22)%0A%20%20%20%20return%20(max_correlation%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%20Inter-channel%20maximum%20correlation%20matrix%0A%0A%20%20%20%20Heatmap%20of%20%24%7C%5Crho_%7B%5Cmax%7D%7C%24%20between%20all%20pairs%20of%20adjugate%20entries.%20Axis%20label%20%24ij%24%20denotes%20the%20adjugate%20entry%20in%20row%20%24i%24%2C%20column%20%24j%24.%20The%20diagonal%20is%20the%20autocorrelation%20(1%20by%20construction)%3B%20low%20off-diagonal%20values%20indicate%20good%20decorrelation.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(correlation_heatmap%2C%20max_correlation%2C%20num_delays)%3A%0A%20%20%20%20_labels%20%3D%20%5B%0A%20%20%20%20%20%20%20%20f%22%7B_k%20%25%20num_delays%20%2B%201%7D%7B_k%20%2F%2F%20num_delays%20%2B%201%7D%22%20for%20_k%20in%20range(num_delays**2)%0A%20%20%20%20%5D%0A%20%20%20%20correlation_heatmap(%0A%20%20%20%20%20%20%20%20max_correlation%2C%0A%20%20%20%20%20%20%20%20_labels%2C%0A%20%20%20%20%20%20%20%20%22Inter-channel%20maximum%20correlation%22%2C%0A%20%20%20%20%20%20%20%20(%22ij%22%2C%20%22kl%22)%2C%0A%20%20%20%20%20%20%20%20(600%2C%20700)%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%20Single%20input%20distributed%20to%20all%20delays%0A%0A%20%20%20%20With%20a%20single%20source%20distributed%20equally%20to%20all%20delay%20lines%20(%24B%20%3D%20%5Cmathbf%7B1%7D%24)%2C%20the%20numerator%20of%20the%20transfer%20function%20collapses%20to%20the%20vector%20%24%5Cmathrm%7Badj%7D(P(z))%5C%2C%5Cmathbf%7B1%7D%24%20%E2%80%94%20one%20FIR%20filter%20per%20output%20channel.%20The%20pairwise%20maximum%20correlation%20among%20these%20%24N%24%20filters%20indicates%20the%20decorrelation%20among%20the%20FDN%20output%20channels%20for%20a%20single%20source.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(adj_mat%2C%20mo%2C%20np%2C%20num_delays%2C%20pyFDN)%3A%0A%20%20%20%20input_gains%20%3D%20np.ones((num_delays%2C%201%2C%201))%0A%20%20%20%20adj_vector%20%3D%20pyFDN.matrix_convolution(adj_mat%2C%20input_gains)%0A%0A%20%20%20%20_fig%2C%20_%2C%20_%20%3D%20pyFDN.plot_impulse_response_matrix(%0A%20%20%20%20%20%20%20%20None%2C%0A%20%20%20%20%20%20%20%20adj_vector.transpose(2%2C%200%2C%201)%2C%0A%20%20%20%20%20%20%20%20xlabel%3D%22Time%20(samples)%22%2C%0A%20%20%20%20%20%20%20%20ylabel%3D%22Sample%20value%22%2C%0A%20%20%20%20%20%20%20%20title%3D%22Adjugate%20vector%20adj(P(z))%20B%20for%20a%20single%20input%22%2C%0A%20%20%20%20%20%20%20%20linewidth%3D0.6%2C%0A%20%20%20%20)%0A%20%20%20%20mo.as_html(_fig)%0A%20%20%20%20return%20(adj_vector%2C)%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20adj_vector%2C%0A%20%20%20%20correlation_heatmap%2C%0A%20%20%20%20num_delays%2C%0A%20%20%20%20pyFDN%2C%0A%20%20%20%20summarise_correlation%2C%0A)%3A%0A%20%20%20%20max_correlation_single%20%3D%20pyFDN.max_corr(adj_vector)%0A%0A%20%20%20%20_median%2C%20_iqr%20%3D%20summarise_correlation(max_correlation_single)%0A%20%20%20%20print(f%22Median%20correlation%20metric%3A%20%7B_median%3A.4f%7D%22)%0A%20%20%20%20print(f%22Interquartile%20range%3A%20%20%20%20%20%20%20%7B_iqr%3A.4f%7D%22)%0A%0A%20%20%20%20correlation_heatmap(%0A%20%20%20%20%20%20%20%20max_correlation_single%2C%0A%20%20%20%20%20%20%20%20%5Bstr(_k%20%2B%201)%20for%20_k%20in%20range(num_delays)%5D%2C%0A%20%20%20%20%20%20%20%20%22Inter-channel%20maximum%20correlation%20%E2%80%94%20single%20input%22%2C%0A%20%20%20%20%20%20%20%20(%22Output%20channel%22%2C%20%22Output%20channel%22)%2C%0A%20%20%20%20%20%20%20%20(450%2C%20520)%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
ea910427d2b98a683b6044932047fb30