diff --git a/figures/fig_invariance_log_hp.pdf b/figures/fig_invariance_log_hp.pdf index 5bf2ab9..6779cd9 100644 Binary files a/figures/fig_invariance_log_hp.pdf and b/figures/fig_invariance_log_hp.pdf differ diff --git a/figures/fig_invariance_thresh_lp.pdf b/figures/fig_invariance_thresh_lp.pdf new file mode 100644 index 0000000..651d1d1 Binary files /dev/null and b/figures/fig_invariance_thresh_lp.pdf differ diff --git a/main.aux b/main.aux index 68937a1..f9a9721 100644 --- a/main.aux +++ b/main.aux @@ -248,7 +248,7 @@ \newlabel{eq:toy_log}{{12}{11}{}{}{}} \newlabel{eq:toy_highpass}{{13}{11}{}{}{}} \newlabel{eq:toy_snr}{{14}{11}{}{}{}} -\@writefile{lof}{\contentsline {figure}{\numberline {4}{\ignorespaces \textbf {Intensity invariance by logarithmic compression and adaptation.} \textbf {a}:~Synthetic envelopes resulting from the mixture of song component $s(t)$ with scale $\alpha $ and noise component $\eta (t)$ with fixed scale. \textbf {b}:~Corresponding logarithmically scaled envelopes. \textbf {c}:~Corresponding intensity-adapted envelopes. \textbf {d}:~Absolute SNRs of each representation relative to the representation without song component ($\alpha =0$). \textbf {e}:~Same SNRs as in \textbf {d} but normalized to the maximum SNR for each representation. \textbf {f}:~Relative amplification of normalized SNRs relative to the normalized SNRs of the initial envelope. }}{12}{}\protected@file@percent } +\@writefile{lof}{\contentsline {figure}{\numberline {4}{\ignorespaces \textbf {Intensity invariance by logarithmic compression and adaptation is restricted by the noise floor.} Synthetic envelope $x_{\text {env}}(t)$ is transformed into logarihmically compressed envelope $x_{\text {dB}}(t)$ and further into intensity-adapted envelope $x_{\text {adapt}}(t)$. Indicated time scale is $5\,$s for both \textbf {a} and \textbf {b} (black bars). \textbf {a}:~Ideally, if $x_{\text {env}}(t)$ consists only of song component $s(t)$ rescaled by $\alpha $, then $x_{\text {adapt}}(t)$ is fully intensity-invariant across all $\alpha $. \textbf {b}:~In practice, $x_{\text {env}}(t)$ also contains fixed-scale noise component $\eta (t)$, which limits the effective intensity invariance of $x_{\text {adapt}}(t)$ to sufficiently large $\alpha $. \textbf {c}:~Ratios of the SD of each representation in \textbf {b} at a given $\alpha $ relative to the SD of the representation for $\alpha =0$ (solid lines). The same ratios for the ideal $x_{\text {adapt}}(t)$ in \textbf {a} are shown for comparison (dashed line). }}{12}{}\protected@file@percent } \newlabel{fig:inv_log-hp}{{4}{12}{}{}{}} \@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Thresholding nonlinearity \& temporal averaging}{12}{}\protected@file@percent } \newlabel{eq:pdf_split}{{15}{13}{}{}{}} diff --git a/main.blg b/main.blg index c795d8b..181867a 100644 --- a/main.blg +++ b/main.blg @@ -1,71 +1,71 @@ [0] Config.pm:307> INFO - This is Biber 2.19 [0] Config.pm:310> INFO - Logfile is 'main.blg' -[38] biber:340> INFO - === Di Mär 3, 2026, 16:21:37 -[45] Biber.pm:419> INFO - Reading 'main.bcf' -[75] Biber.pm:979> INFO - Found 55 citekeys in bib section 0 -[82] Biber.pm:4419> INFO - Processing section 0 -[87] Biber.pm:4610> INFO - Looking for bibtex file 'cite.bib' for section 0 -[88] bibtex.pm:1713> INFO - LaTeX decoding ... -[120] bibtex.pm:1519> INFO - Found BibTeX data source 'cite.bib' -[303] UCollate.pm:68> INFO - Overriding locale 'en-US' defaults 'normalization = NFD' with 'normalization = prenormalized' -[303] UCollate.pm:68> INFO - Overriding locale 'en-US' defaults 'variable = shifted' with 'variable = non-ignorable' -[303] Biber.pm:4239> INFO - Sorting list 'nyt/global//global/global' of type 'entry' with template 'nyt' and locale 'en-US' -[303] Biber.pm:4245> INFO - No sort tailoring available for locale 'en-US' -[327] bbl.pm:660> INFO - Writing 'main.bbl' with encoding 'UTF-8' -[337] bbl.pm:763> INFO - Output to main.bbl -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 10, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 21, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 38, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 49, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 58, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 73, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 82, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 91, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 100, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 109, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 118, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 127, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 136, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 157, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 178, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 187, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 196, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 207, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 218, warning: 6 characters of junk seen at toplevel -[337] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 229, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 240, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 249, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 258, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 269, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 278, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 289, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 300, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 309, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 328, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 337, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 400, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 419, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 428, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 437, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 456, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 491, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 526, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 535, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 556, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 565, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 576, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 587, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 619, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 648, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 658, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 667, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 688, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 709, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 720, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 729, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 749, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 766, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 775, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 800, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_rB4F/347c261ec4135a5723bef5c751f5078f_81147.utf8, line 817, warning: 6 characters of junk seen at toplevel -[338] Biber.pm:133> INFO - WARNINGS: 55 +[35] biber:340> INFO - === Fr Mär 6, 2026, 10:37:34 +[43] Biber.pm:419> INFO - Reading 'main.bcf' +[71] Biber.pm:979> INFO - Found 55 citekeys in bib section 0 +[76] Biber.pm:4419> INFO - Processing section 0 +[81] Biber.pm:4610> INFO - Looking for bibtex file 'cite.bib' for section 0 +[82] bibtex.pm:1713> INFO - LaTeX decoding ... +[111] bibtex.pm:1519> INFO - Found BibTeX data source 'cite.bib' +[280] UCollate.pm:68> INFO - Overriding locale 'en-US' defaults 'normalization = NFD' with 'normalization = prenormalized' +[280] UCollate.pm:68> INFO - Overriding locale 'en-US' defaults 'variable = shifted' with 'variable = non-ignorable' +[280] Biber.pm:4239> INFO - Sorting list 'nyt/global//global/global' of type 'entry' with template 'nyt' and locale 'en-US' +[280] Biber.pm:4245> INFO - No sort tailoring available for locale 'en-US' +[303] bbl.pm:660> INFO - Writing 'main.bbl' with encoding 'UTF-8' +[313] bbl.pm:763> INFO - Output to main.bbl +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 10, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 21, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 38, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 49, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 58, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 73, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 82, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 91, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 100, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 109, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 118, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 127, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 136, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 157, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 178, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 187, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 196, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 207, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 218, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 229, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 240, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 249, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 258, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 269, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 278, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 289, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 300, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 309, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 328, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 337, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 400, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 419, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 428, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 437, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 456, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 491, warning: 6 characters of junk seen at toplevel +[313] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 526, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 535, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 556, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 565, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 576, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 587, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 619, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 648, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 658, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 667, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 688, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 709, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 720, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 729, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 749, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 766, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 775, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 800, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:131> WARN - BibTeX subsystem: /tmp/biber_tmp_YENa/347c261ec4135a5723bef5c751f5078f_27143.utf8, line 817, warning: 6 characters of junk seen at toplevel +[314] Biber.pm:133> INFO - WARNINGS: 55 diff --git a/main.fdb_latexmk b/main.fdb_latexmk index b88dca6..56ff0f8 100644 --- a/main.fdb_latexmk +++ b/main.fdb_latexmk @@ -1,14 +1,14 @@ # Fdb version 4 -["biber main"] 1772551296.80409 "main.bcf" "main.bbl" "main" 1772551360.62635 0 +["biber main"] 1772789854.19015 "main.bcf" "main.bbl" "main" 1772789995.6149 0 "cite.bib" 1770904753.08918 27483 4290db0c91f7b5055e25472ef913f6b4 "" - "main.bcf" 1772551360.57805 112931 2a478116d80ebb1ada7083a24facd6e3 "pdflatex" + "main.bcf" 1772789995.56243 112931 2a478116d80ebb1ada7083a24facd6e3 "pdflatex" (generated) "main.bbl" "main.blg" (rewritten before read) -["pdflatex"] 1772551359.77359 "/home/hartling/phd/paper/paper_2025/main.tex" "main.pdf" "main" 1772551360.62655 0 +["pdflatex"] 1772789994.76445 "/home/hartling/phd/paper/paper_2025/main.tex" "main.pdf" "main" 1772789995.6151 0 "/etc/texmf/web2c/texmf.cnf" 1761560044.43676 475 c0e671620eb5563b2130f56340a5fde8 "" - "/home/hartling/phd/paper/paper_2025/main.tex" 1772551358.81608 44727 89099053313a739a124eef0ebf096cbe "" + "/home/hartling/phd/paper/paper_2025/main.tex" 1772789993.80744 45115 2fcef2652b25ea1193a94494b1d1cf7c "" "/usr/share/texlive/texmf-dist/fonts/map/fontname/texfonts.map" 1577235249 3524 cb3e574dea2d1052e39280babc910dc8 "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm" 1246382020 1004 54797486969f23fa377b128694d548df "" "/usr/share/texlive/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex8.tfm" 1246382020 988 bdf658c3bfc2d96d3c8b02cfc1c94c20 "" @@ -153,12 +153,12 @@ "/var/lib/texmf/web2c/pdftex/pdflatex.fmt" 1761648508 8213325 7fd20752ab46ff9aa583e4973d7433df "" "figures/fig_auditory_pathway.pdf" 1771593904.14638 1153923 3df8539421fd21dc866cc8d320bd9b1d "" "figures/fig_feat_stages.pdf" 1771841347.81651 8600157 89f9276167cc096f9adce052152edd70 "" - "figures/fig_invariance_log_hp.pdf" 1772550242.81975 596132 199b6299bddb7a18add3f3c606c26c68 "" + "figures/fig_invariance_log_hp.pdf" 1772787211.70944 478408 0ea1912229a93b394b158fd92257a66d "" "figures/fig_pre_stages.pdf" 1771841345.77353 440442 263f9bd4a3bca8e0653ac0a4c4a8da2c "" - "main.aux" 1772551360.57305 12621 fd60ae2568ab59c6c47a0013f596c4ce "pdflatex" - "main.bbl" 1772551297.4309 91039 1380dc8c93d2855fdb132cc5a40ad52f "biber main" - "main.run.xml" 1772551360.57905 2335 a049bc26a7f032e842ce55de5bc38328 "pdflatex" - "main.tex" 1772551358.81608 44727 89099053313a739a124eef0ebf096cbe "" + "main.aux" 1772789995.55643 12988 64d0311586c567b693d9506c6c12b5dd "pdflatex" + "main.bbl" 1772789854.78352 91039 1380dc8c93d2855fdb132cc5a40ad52f "biber main" + "main.run.xml" 1772789995.56243 2335 a049bc26a7f032e842ce55de5bc38328 "pdflatex" + "main.tex" 1772789993.80744 45115 2fcef2652b25ea1193a94494b1d1cf7c "" (generated) "main.aux" "main.bcf" diff --git a/main.log b/main.log index e23bb36..92ba3cb 100644 --- a/main.log +++ b/main.log @@ -1,4 +1,4 @@ -This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023/Debian) (preloaded format=pdflatex 2025.10.28) 3 MAR 2026 16:22 +This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023/Debian) (preloaded format=pdflatex 2025.10.28) 6 MAR 2026 10:39 entering extended mode restricted \write18 enabled. file:line:error style messages enabled. @@ -784,11 +784,11 @@ Here is how much of TeX's memory you used: 42715 multiletter control sequences out of 15000+600000 569394 words of font info for 79 fonts, out of 8000000 for 9000 1143 hyphenation exceptions out of 8191 - 94i,19n,93p,955b,1732s stack positions out of 10000i,1000n,20000p,200000b,200000s + 94i,19n,93p,1224b,1732s stack positions out of 10000i,1000n,20000p,200000b,200000s -Output written on main.pdf (15 pages, 10953973 bytes). +Output written on main.pdf (15 pages, 10838053 bytes). PDF statistics: - 1299 PDF objects out of 1440 (max. 8388607) + 1290 PDF objects out of 1440 (max. 8388607) 764 compressed objects within 8 object streams 0 named destinations out of 1000 (max. 500000) 33 words of extra memory for PDF output out of 10000 (max. 10000000) diff --git a/main.pdf b/main.pdf index e61acfc..a77bfc4 100644 Binary files a/main.pdf and b/main.pdf differ diff --git a/main.synctex.gz b/main.synctex.gz index 89e5e59..476c8b7 100644 Binary files a/main.synctex.gz and b/main.synctex.gz differ diff --git a/main.tex b/main.tex index 3647a2c..f89ac4f 100644 --- a/main.tex +++ b/main.tex @@ -624,18 +624,24 @@ the signal for reliable song recognition. \centering \includegraphics[width=\textwidth]{figures/fig_invariance_log_hp.pdf} \caption{\textbf{Intensity invariance by logarithmic compression and - adaptation.} - \textbf{a}:~Synthetic envelopes resulting from the - mixture of song component $\soc(t)$ with scale $\sca$ and - noise component $\noc(t)$ with fixed scale. - \textbf{b}:~Corresponding logarithmically scaled envelopes. - \textbf{c}:~Corresponding intensity-adapted envelopes. - \textbf{d}:~Absolute SNRs of each representation relative - to the representation without song component ($\sca=0$). - \textbf{e}:~Same SNRs as in \textbf{d} but normalized to - the maximum SNR for each representation. - \textbf{f}:~Relative amplification of normalized SNRs - relative to the normalized SNRs of the initial envelope. + adaptation is restricted by the noise floor.} + Synthetic envelope $\env(t)$ is transformed into + logarihmically compressed envelope $\db(t)$ and further + into intensity-adapted envelope $\adapt(t)$. Indicated + time scale is $5\,$s for both \textbf{a} and \textbf{b} + (black bars). + \textbf{a}:~Ideally, if $\env(t)$ consists only of song + component $\soc(t)$ rescaled by $\sca$, then $\adapt(t)$ + is fully intensity-invariant across all $\sca$. + \textbf{b}:~In practice, $\env(t)$ also contains + fixed-scale noise component $\noc(t)$, which limits the + effective intensity invariance of $\adapt(t)$ to + sufficiently large $\sca$. + \textbf{c}:~Ratios of the SD of each representation in + \textbf{b} at a given $\sca$ relative to the SD of the + representation for $\sca=0$ (solid lines). The same ratios + for the ideal $\adapt(t)$ in \textbf{a} are shown for + comparison (dashed line). } \label{fig:inv_log-hp} \end{figure} diff --git a/python/fig_invariance_log-hp.py b/python/fig_invariance_log-hp.py index a972f66..7d45678 100644 --- a/python/fig_invariance_log-hp.py +++ b/python/fig_invariance_log-hp.py @@ -1,224 +1,281 @@ import plotstyle_plt -import glob import numpy as np import matplotlib.pyplot as plt +from matplotlib.transforms import BboxTransformTo from itertools import product +from thunderhopper.filetools import search_files from thunderhopper.modeltools import load_data from color_functions import load_colors -from plot_functions import hide_axis, letter_subplots, ylimits, ylabel, super_xlabel, plot_line +from plot_functions import hide_axis, ylimits, xlabel, ylabel, plot_line, strip_zeros from IPython import embed -def strip_zeros(num, right_digits=5): - if isinstance(num, int): - return num - num = f'{num:.{right_digits}f}' - left, right = num.split('.') - right = right.rstrip('0') - if right: - return f'{left}.{right}' - return left - -def plot_snippets(axes, time, snippets, label, scales=None, - ymin=None, ymax=None, **kwargs): - ymin, ymax = ylimits(snippets, minval=ymin, maxval=ymax, pad=0.05) - ylabel(axes[0], label, x=-0.7, rotation=0, ha='left', va='center') - for i, (ax, snippet) in enumerate(zip(axes, snippets.T)): - plot_line(ax, time, snippet, ymin=ymin, ymax=ymax, **kwargs) - if scales is not None: - ax.set_title(f'$\\alpha={strip_zeros(scales[i])}$') +def time_bar(ax, dur, y0=0.9, y1=0.95, xshift=0.5, parent=None, transform=None, **kwargs): + t0, t1 = ax.get_xlim() + offset = (t1 - t0 - dur) * xshift + x0 = t0 + offset + x1 = x0 + dur + if parent is None: + parent = ax + if transform is None: + transform = BboxTransformTo(parent.bbox) + if transform is not ax.transData: + trans = ax.transData + transform.inverted() + x0 = trans.transform((x0, 0))[0] + x1 = trans.transform((x1, 0))[0] + parent.add_artist(plt.Rectangle((x0, y0), x1 - x0, y1 - y0, + transform=transform, **kwargs)) return None +def add_snip_axes(fig, grid_kwargs): + grid = fig.add_gridspec(**grid_kwargs) + axes = np.zeros((grid.nrows, grid.ncols), dtype=object) + for i, j in product(range(grid.nrows), range(grid.ncols)): + axes[i, j] = fig.add_subplot(grid[i, j]) + [hide_axis(ax, 'left') for ax in axes.flatten()] + [hide_axis(ax, 'bottom') for ax in axes.flatten()] + return axes + +def plot_snippets(axes, time, snippets, ymin=None, ymax=None, **kwargs): + ymin, ymax = ylimits(snippets, minval=ymin, maxval=ymax, pad=0.05) + for ax, snippet in zip(axes, snippets.T): + plot_line(ax, time, snippet, ymin=ymin, ymax=ymax, **kwargs) + return None + + # GENERAL SETTINGS: target = 'Omocestus_rufipes' -data_paths = glob.glob(f'../data/inv/log_hp/{target}*.npz') +data_paths = search_files(target, excl='noise', dir='../data/inv/log_hp/') stages = ['env', 'log', 'inv'] -files = stages + ['scales', 'plot_scales', 'snr_env', 'snr_log', 'snr_inv'] +files = stages + ['scales', 'example_scales', 'limit', + 'measure_env', 'measure_log', 'measure_inv'] save_path = '../figures/fig_invariance_log_hp.pdf' -# PLOT SETTINGS: +# GRAPH SETTINGS: fig_kwargs = dict( figsize=(32/2.54, 16/2.54), ) -grid1_kwargs = dict( +super_grid_kwargs = dict( + nrows=2, + ncols=2, + wspace=0, + hspace=0, + left=0, + right=1, + bottom=0, + top=1 +) +subfig_specs = dict( + pure=(0, 0), + noise=(1, 0), + analysis=(slice(None), 1) +) +pure_grid_kwargs = dict( nrows=len(stages), ncols=None, wspace=0.05, - hspace=0.3, - left=0.1, - right=0.985, - bottom=0.17, + hspace=0.1, + left=0.13, + right=0.95, + bottom=0.15, top=0.9 ) -grid2_kwargs = dict( +noise_grid_kwargs = dict( + nrows=len(stages), + ncols=None, + wspace=0.05, + hspace=0.1, + left=0.13, + right=0.95, + bottom=0.15, + top=0.9 +) +analysis_grid_kwargs = dict( nrows=1, - ncols=3, - wspace=0.35, + ncols=1, + wspace=0, hspace=0, - left=0.1, - right=0.985, - bottom=0.18, + left=0.15, + right=0.96, + bottom=0.1, top=0.95 ) +snip_specs = dict( + env=(0, slice(None)), + log=(1, slice(None)), + inv=(2, slice(None)) +) + +# PLOT SETTINGS: colors = load_colors('../data/stage_colors.npz') -lw_snippets = 0.25 +lw_snippets = 0.5 lw_analysis = 3 +xlabels = dict( + analysis='scale $\\alpha$', +) +xlab_analysis_kwargs = dict( + y=0.01, + fontsize=16, + ha='center', + va='bottom', +) ylabels = dict( - env=r'$x_{\text{env}}$', - log=r'$x_{\text{dB}}$', - inv=r'$x_{\text{adapt}}$', - abs='abs. SNR',#'abs. ' + r'$\text{SNR}$', - norm='norm. SNR',#'norm. ' + r'$\text{SNR}$', - gain='rel. SNR gain' + env='$x_{\\text{env}}$', + log='$x_{\\text{dB}}$', + inv='$x_{\\text{adapt}}$', + analysis='ratio $\\text{SD}_{\\alpha}\\,/\\,\\text{SD}_{\\min[\\alpha]}$', + # analysis='ratio $\\sigma_{\\alpha}\\,/\\,\\sigma_{\\min[\\alpha]}$', +) +ylab_snip_kwargs = dict( + x=0.01, + fontsize=20, + rotation=0, + ha='left', + va='center', +) +ylab_analysis_kwargs = dict( + x=0.02, + fontsize=16, + ha='center', + va='top', ) xloc = dict( - abs=5, + analysis=200, ) -yloc = dict( - env=100, - log=10, - inv=5, - abs=50, -) -letter_kwargs = dict( - x=0.03, - y=0.99, +letter_snip_kwargs = dict( + x=0.02, + y=1, ha='left', - va='top' + va='top', + fontsize=22, + fontweight='bold' ) -fit_kwargs = dict( - c='darkred', - ls='--', - zorder=1.9 +letter_analysis_kwargs = dict( + x=0, + y=1, + ha='left', + va='top', + fontsize=22, + fontweight='bold' ) -fit_lw = dict( - abs=6, - norm=3, - gain=3 -) -text_kwargs = dict( - abs=dict(s='$\\alpha^2+1$', fontsize=16, c=fit_kwargs['c'], - x=0.85, y=0.9, ha='right', va='center'), - norm=dict(s='$\\alpha^2+1$', fontsize=16, c=fit_kwargs['c'], - x=0.85, y=0.9, ha='right', va='center'), - gain=dict(s='$\\frac{1}{\\alpha}$', fontsize=24, c=fit_kwargs['c'], - x=0.75, y=0.8, ha='left', va='center') -) -calculated_floor = False -floor_kwargs = dict( - xmin=0, +indicate_unsaturated = False +unsaturated_proportion = 0.85 +unsaturated_kwargs = dict( color=3 * (0.85,), zorder=0, lw=0 ) +bar_time = 5 +bar_kwargs = dict( + y0=0.5, + y1=0.6, + color='k', + lw = 0, +) # EXECUTION: for data_path in data_paths: print(f'Processing {data_path}') # Load invariance data: - data, config = load_data(data_path, files) - t_full = np.arange(data['env'].shape[0]) / config['env_rate'] - nonzero_scales = data['scales'][data['scales'] > 0] - floor_kwargs['xmax'] = data['floor_scale'] if calculated_floor else 1 + pure_data, config = load_data(data_path, files) + noise_data, _ = load_data(data_path.replace('.npz', '_noise.npz'), files) + t_full = np.arange(pure_data['env'].shape[0]) / config['env_rate'] # Prepare overall graph: fig = plt.figure(**fig_kwargs) - super_grid = fig.add_gridspec(2, 1, wspace=0, hspace=1, - left=0, right=1, bottom=0, top=1) + super_grid = fig.add_gridspec(**super_grid_kwargs) - # Prepare snippet axes: - subfig1 = fig.add_subfigure(super_grid[0, :]) - grid1_kwargs['ncols'] = data['plot_scales'].size - grid1 = subfig1.add_gridspec(**grid1_kwargs) - axes = np.zeros((grid1.nrows, grid1.ncols), dtype=object) - for i, j in product(range(grid1.nrows), range(grid1.ncols)): - axes[i, j] = subfig1.add_subplot(grid1[i, j]) - [hide_axis(ax, 'bottom') for ax in axes[:-1, :].flatten()] - [hide_axis(ax, 'left') for ax in axes[:, 1:].flatten()] - super_xlabel('time [s]', subfig1, axes[-1, 0], axes[-1, -1], y=0) - letter_subplots(axes[:, 0], labels='abc', **letter_kwargs) + # Prepare pure-song snippet axes: + pure_subfig = fig.add_subfigure(super_grid[subfig_specs['pure']]) + pure_grid_kwargs['nrows' if pure_grid_kwargs['nrows'] is None else 'ncols'] = pure_data['example_scales'].size + pure_axes = add_snip_axes(pure_subfig, pure_grid_kwargs) + for ax, stage in zip(pure_axes[:, 0], stages): + ylabel(ax, ylabels[stage], **ylab_snip_kwargs, + transform=pure_subfig.transSubfigure) + for ax, scale in zip(pure_axes[snip_specs['env']], pure_data['example_scales']): + ax.set_title(f'$\\alpha={strip_zeros(scale)}$') + pure_subfig.text(s='a', **letter_snip_kwargs) - # Prepare analysis axes: - subfig2 = fig.add_subfigure(super_grid[1, :]) - grid2 = subfig2.add_gridspec(**grid2_kwargs) - symlog_kwargs = dict(linthresh=nonzero_scales.min(), linscale=0.2) + # Prepare noise-song snippet axes: + noise_subfig = fig.add_subfigure(super_grid[subfig_specs['noise']]) + noise_grid_kwargs['nrows' if noise_grid_kwargs['nrows'] is None else 'ncols'] = noise_data['example_scales'].size + noise_grid = noise_subfig.add_gridspec(**noise_grid_kwargs) + noise_axes = add_snip_axes(noise_subfig, noise_grid_kwargs) + for ax, stage in zip(noise_axes[:, 0], stages): + ylabel(ax, ylabels[stage], **ylab_snip_kwargs, + transform=noise_subfig.transSubfigure) + for ax, scale in zip(noise_axes[snip_specs['env']], noise_data['example_scales']): + ax.set_title(f'$\\alpha={strip_zeros(scale)}$') + noise_subfig.text(s='b', **letter_snip_kwargs) - ax_abs_snr = subfig2.add_subplot(grid2[:, 0]) - ax_abs_snr.set_ylabel(ylabels['abs']) + # Prepare analysis axis: + analysis_subfig = fig.add_subfigure(super_grid[subfig_specs['analysis']]) + analysis_grid = analysis_subfig.add_gridspec(**analysis_grid_kwargs) + analysis_ax = analysis_subfig.add_subplot(analysis_grid[0, 0]) + analysis_ax.set_xlim(noise_data['scales'].min(), noise_data['scales'].max()) + analysis_ax.xaxis.set_major_locator(plt.MultipleLocator(xloc['analysis'])) + xlabel(analysis_ax, xlabels['analysis'], **xlab_analysis_kwargs, + transform=analysis_subfig.transSubfigure) + analysis_ax.set_yscale('log') + ylabel(analysis_ax, ylabels['analysis'], **ylab_analysis_kwargs, + transform=analysis_subfig.transSubfigure) + analysis_subfig.text(s='c', **letter_analysis_kwargs) - ax_norm_snr = subfig2.add_subplot(grid2[:, 1]) - ax_norm_snr.set_ylabel(ylabels['norm']) - ax_norm_snr.set_xscale('symlog', **symlog_kwargs) - ax_norm_snr.set_yscale('log') + # Plot pure-song envelope snippets: + plot_snippets(pure_axes[snip_specs['env']], t_full, pure_data['env'], + ymin=0, c=colors['env'], lw=lw_snippets) - ax_gain = subfig2.add_subplot(grid2[:, 2]) - ax_gain.set_ylabel(ylabels['gain']) - ax_gain.set_xscale('symlog', **symlog_kwargs) - ax_gain.set_yscale('log') - super_xlabel('song scale $\\alpha$', subfig2, ax_abs_snr, ax_gain) - letter_subplots([ax_abs_snr, ax_norm_snr, ax_gain], labels='def', **letter_kwargs) + # Plot pure-song logarithmic snippets: + plot_snippets(pure_axes[snip_specs['log']], t_full, pure_data['log'], + ymax=None, c=colors['log'], lw=lw_snippets) - # Plot envelope snippets: - plot_snippets(axes[0, :], t_full, data['env'], ylabels['env'], ymin=0, - scales=data['plot_scales'], c=colors['env'], lw=lw_snippets) - axes[0, 0].yaxis.set_major_locator(plt.MultipleLocator(yloc['env'])) - - # Plot logarithmic snippets: - plot_snippets(axes[1, :], t_full, data['log'], ylabels['log'], ymax=0, - c=colors['log'], lw=lw_snippets) - axes[1, 0].yaxis.set_major_locator(plt.MultipleLocator(yloc['log'])) - - # Plot invariant snippets: - plot_snippets(axes[2, :], t_full, data['inv'], ylabels['inv'], + # Plot pure-song invariant snippets: + plot_snippets(pure_axes[snip_specs['inv']], t_full, pure_data['inv'], c=colors['inv'], lw=lw_snippets) - axes[2, 0].yaxis.set_major_locator(plt.MultipleLocator(yloc['inv'])) - # Plot in-representation SNRs (absolute): - ax_abs_snr.plot(data['scales'], data['snr_env'], c=colors['env'], lw=lw_analysis) - ax_abs_snr.plot(data['scales'], data['snr_log'], c=colors['log'], lw=lw_analysis) - ax_abs_snr.plot(data['scales'], data['snr_inv'], c=colors['inv'], lw=lw_analysis) - ax_abs_snr.axvspan(**floor_kwargs) - ax_abs_snr.xaxis.set_major_locator(plt.MultipleLocator(xloc['abs'])) - ax_abs_snr.yaxis.set_major_locator(plt.MultipleLocator(yloc['abs'])) - ax_abs_snr.set_ylim(0, data['snr_env'].max()) + # Indicate time scale: + time_bar(pure_axes[snip_specs['env']][0], bar_time, **bar_kwargs) - # Plot envelope SNR fit: - ax_abs_snr.plot(data['scales'], data['scales'] ** 2 + 1, - lw=fit_lw['abs'], **fit_kwargs) - ax_abs_snr.text(transform=ax_abs_snr.transAxes, **text_kwargs['abs']) + # Plot noise-song envelope snippets: + plot_snippets(noise_axes[snip_specs['env']], t_full, noise_data['env'], + ymin=0, c=colors['env'], lw=lw_snippets) - # Get normalized SNRs: - norm_snr_env = data['snr_env'] / data['snr_env'].max() - norm_snr_log = data['snr_log'] / data['snr_log'].max() - norm_snr_inv = data['snr_inv'] / data['snr_inv'].max() + # Plot noise-song logarithmic snippets: + plot_snippets(noise_axes[snip_specs['log']], t_full, noise_data['log'], + ymax=None, c=colors['log'], lw=lw_snippets) - # Plot in-representation SNRs (normalized): - ax_norm_snr.plot(data['scales'], norm_snr_env, c=colors['env'], lw=lw_analysis) - ax_norm_snr.plot(data['scales'], norm_snr_log, c=colors['log'], lw=lw_analysis) - ax_norm_snr.plot(data['scales'], norm_snr_inv, c=colors['inv'], lw=lw_analysis) - ax_norm_snr.axvspan(**floor_kwargs) - ax_norm_snr.set_ylim(norm_snr_env.min(), 1) + # Plot noise-song invariant snippets: + plot_snippets(noise_axes[snip_specs['inv']], t_full, noise_data['inv'], + c=colors['inv'], lw=lw_snippets) - # # Plot envelope SNR fit: - # ax_norm_snr.plot(nonzero_scales, nonzero_scales / nonzero_scales.max(), - # lw=fit_lw['norm'], **fit_kwargs) - # ax_norm_snr.text(transform=ax_norm_snr.transAxes, **text_kwargs['norm']) + # Indicate time scale: + time_bar(noise_axes[snip_specs['env']][0], bar_time, **bar_kwargs) - # Get relative SNR gain: - gain_log = norm_snr_log / norm_snr_env - gain_inv = norm_snr_inv / norm_snr_env + # Plot pure-song SD ratios (ideal): + base_ind = np.argmin(pure_data['scales']) + # measure_env = pure_data['measure_env'] / pure_data['measure_env'][base_ind] + # measure_log = pure_data['measure_log'] / pure_data['measure_log'][base_ind] + measure_inv = pure_data['measure_inv'] / pure_data['measure_inv'][base_ind] + # analysis_ax.plot(pure_data['scales'], measure_env, c=colors['env'], lw=lw_analysis, ls='--') + # analysis_ax.plot(pure_data['scales'], measure_log, c=colors['log'], lw=lw_analysis, ls='--') + analysis_ax.plot(pure_data['scales'], measure_inv, c=colors['inv'], lw=lw_analysis, ls='--') - # Plot across-representation gain: - ax_gain.plot(data['scales'], gain_log, c=colors['log'], lw=lw_analysis) - ax_gain.plot(data['scales'], gain_inv, c=colors['inv'], lw=lw_analysis) - ax_gain.axvspan(**floor_kwargs) - ax_gain.set_ylim(1, 10) + if indicate_unsaturated: + # Indicate influence of noise floor: + limit = noise_data['limit'] * unsaturated_proportion + thresh_ind = np.nonzero(noise_data['measure_inv'] <= limit)[0][-1] + analysis_ax.axvspan(0, noise_data['scales'][thresh_ind], **unsaturated_kwargs) + + # Plot noise-song SD ratios (limited): + base_ind = np.argmin(noise_data['scales']) + measure_env = noise_data['measure_env'] / noise_data['measure_env'][base_ind] + measure_log = noise_data['measure_log'] / noise_data['measure_log'][base_ind] + measure_inv = noise_data['measure_inv'] / noise_data['measure_inv'][base_ind] + analysis_ax.plot(noise_data['scales'], measure_env, c=colors['env'], lw=lw_analysis) + analysis_ax.plot(noise_data['scales'], measure_log, c=colors['log'], lw=lw_analysis) + analysis_ax.plot(noise_data['scales'], measure_inv, c=colors['inv'], lw=lw_analysis) + analysis_ax.set_ylim(0.1, measure_env.max()) - # Plot amplification fit: - ax_gain.plot(nonzero_scales, nonzero_scales.max() / nonzero_scales, - lw=fit_lw['gain'], **fit_kwargs) - ax_gain.text(transform=ax_gain.transAxes, **text_kwargs['gain']) - if save_path is not None: fig.savefig(save_path) plt.show() diff --git a/python/fig_invariance_thresh-lp.py b/python/fig_invariance_thresh-lp.py new file mode 100644 index 0000000..1ca102e --- /dev/null +++ b/python/fig_invariance_thresh-lp.py @@ -0,0 +1,285 @@ +from pyparsing import alphanums + +import plotstyle_plt +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.transforms import BboxTransformTo +from itertools import product +from thunderhopper.filetools import search_files +from thunderhopper.modeltools import load_data +from color_functions import load_colors +from plot_functions import hide_axis, ylimits, xlabel, ylabel, plot_line, plot_barcode, strip_zeros +from IPython import embed + +def time_bar(ax, dur, y0=0.9, y1=0.95, xshift=0.5, parent=None, transform=None, **kwargs): + t0, t1 = ax.get_xlim() + offset = (t1 - t0 - dur) * xshift + x0 = t0 + offset + x1 = x0 + dur + if parent is None: + parent = ax + if transform is None: + transform = BboxTransformTo(parent.bbox) + if transform is not ax.transData: + trans = ax.transData + transform.inverted() + x0 = trans.transform((x0, 0))[0] + x1 = trans.transform((x1, 0))[0] + parent.add_artist(plt.Rectangle((x0, y0), x1 - x0, y1 - y0, + transform=transform, **kwargs)) + return None + +def add_snip_axes(fig, grid_kwargs): + grid = fig.add_gridspec(**grid_kwargs) + axes = np.zeros((grid.nrows, grid.ncols), dtype=object) + for i, j in product(range(grid.nrows), range(grid.ncols)): + axes[i, j] = fig.add_subplot(grid[i, j]) + [hide_axis(ax, 'left') for ax in axes.flatten()] + [hide_axis(ax, 'bottom') for ax in axes.flatten()] + return axes + +def plot_snippets(axes, time, snippets, ymin=None, ymax=None, **kwargs): + ymin, ymax = ylimits(snippets, minval=ymin, maxval=ymax, pad=0.05) + for ax, snippet in zip(axes, snippets.T): + plot_line(ax, time, snippet, ymin=ymin, ymax=ymax, **kwargs) + return None + +def plot_bi_snippets(axes, time, binary, **kwargs): + for ax, binary in zip(axes, binary.T): + plot_barcode(ax, time, binary[:, None], **kwargs) + return None + + +# GENERAL SETTINGS: +target = 'Omocestus_rufipes' +data_paths = search_files(target, excl='noise', dir='../data/inv/thresh_lp/') +stages = ['conv', 'bi', 'feat'] +files = stages + ['scales', 'example_scales', 'measure_conv', 'spread_conv', + 'measure_feat', 'spread_feat'] +save_path = '../figures/fig_invariance_thresh_lp.pdf' + +# GRAPH SETTINGS: +fig_kwargs = dict( + figsize=(32/2.54, 16/2.54), +) +super_grid_kwargs = dict( + nrows=2, + ncols=2, + wspace=0, + hspace=0, + left=0, + right=1, + bottom=0, + top=1 +) +subfig_specs = dict( + pure=(0, 0), + noise=(1, 0), + analysis=(slice(None), 1) +) +pure_grid_kwargs = dict( + nrows=len(stages), + ncols=None, + wspace=0.05, + hspace=0.1, + left=0.13, + right=0.95, + bottom=0.15, + top=0.9 +) +noise_grid_kwargs = dict( + nrows=len(stages), + ncols=None, + wspace=0.05, + hspace=0.1, + left=0.13, + right=0.95, + bottom=0.15, + top=0.9 +) +analysis_grid_kwargs = dict( + nrows=1, + ncols=1, + wspace=0, + hspace=0, + left=0.15, + right=0.96, + bottom=0.1, + top=0.95 +) +snip_specs = dict( + conv=(0, slice(None)), + bi=(1, slice(None)), + feat=(2, slice(None)) +) + +# PLOT SETTINGS: +colors = load_colors('../data/stage_colors.npz') +lw_snippets = 0.5 +lw_analysis = 3 +xlabels = dict( + analysis='scale $\\alpha$', +) +xlab_analysis_kwargs = dict( + y=0.01, + fontsize=16, + ha='center', + va='bottom', +) +ylabels = dict( + conv='$c_i$', + bi='$b_i$', + feat='$f_i$', + analysis='ratio $\\text{SD}_{\\alpha}\\,/\\,\\text{SD}_{\\min[\\alpha]}$', + # analysis='ratio $\\sigma_{\\alpha}\\,/\\,\\sigma_{\\min[\\alpha]}$', +) +ylab_snip_kwargs = dict( + x=0.01, + fontsize=20, + rotation=0, + ha='left', + va='center', +) +ylab_analysis_kwargs = dict( + x=0.02, + fontsize=16, + ha='center', + va='top', +) +xloc = dict( + analysis=10, +) +letter_snip_kwargs = dict( + x=0.02, + y=1, + ha='left', + va='top', + fontsize=22, + fontweight='bold' +) +letter_analysis_kwargs = dict( + x=0, + y=1, + ha='left', + va='top', + fontsize=22, + fontweight='bold' +) +bar_time = 5 +bar_kwargs = dict( + y0=0.5, + y1=0.6, + color='k', + lw = 0, +) +spread_kwargs = dict( + alpha=0.3, + lw=0, + zorder=0 +) +kernel_ind = 0 + +# EXECUTION: +for data_path in data_paths: + print(f'Processing {data_path}') + + # Load invariance data: + pure_data, config = load_data(data_path, files) + noise_data, _ = load_data(data_path.replace('.npz', '_noise.npz'), files) + t_full = np.arange(pure_data['conv'].shape[0]) / config['env_rate'] + + # Reduce snippet data to kernel subset: + pure_data['conv'] = pure_data['conv'][:, kernel_ind] + pure_data['bi'] = pure_data['bi'][:, kernel_ind] + pure_data['feat'] = pure_data['feat'][:, kernel_ind] + noise_data['conv'] = noise_data['conv'][:, kernel_ind] + noise_data['bi'] = noise_data['bi'][:, kernel_ind] + noise_data['feat'] = noise_data['feat'][:, kernel_ind] + + # Prepare overall graph: + fig = plt.figure(**fig_kwargs) + super_grid = fig.add_gridspec(**super_grid_kwargs) + + # Prepare pure-song snippet axes: + pure_subfig = fig.add_subfigure(super_grid[subfig_specs['pure']]) + pure_grid_kwargs['nrows' if pure_grid_kwargs['nrows'] is None else 'ncols'] = pure_data['example_scales'].size + pure_axes = add_snip_axes(pure_subfig, pure_grid_kwargs) + for ax, stage in zip(pure_axes[:, 0], stages): + ylabel(ax, ylabels[stage], **ylab_snip_kwargs, + transform=pure_subfig.transSubfigure) + for ax, scale in zip(pure_axes[snip_specs['conv']], pure_data['example_scales']): + ax.set_title(f'$\\alpha={strip_zeros(scale)}$') + pure_subfig.text(s='a', **letter_snip_kwargs) + + # Prepare noise-song snippet axes: + noise_subfig = fig.add_subfigure(super_grid[subfig_specs['noise']]) + noise_grid_kwargs['nrows' if noise_grid_kwargs['nrows'] is None else 'ncols'] = noise_data['example_scales'].size + noise_grid = noise_subfig.add_gridspec(**noise_grid_kwargs) + noise_axes = add_snip_axes(noise_subfig, noise_grid_kwargs) + for ax, stage in zip(noise_axes[:, 0], stages): + ylabel(ax, ylabels[stage], **ylab_snip_kwargs, + transform=noise_subfig.transSubfigure) + for ax, scale in zip(noise_axes[snip_specs['conv']], noise_data['example_scales']): + ax.set_title(f'$\\alpha={strip_zeros(scale)}$') + noise_subfig.text(s='b', **letter_snip_kwargs) + + # Prepare analysis axis: + analysis_subfig = fig.add_subfigure(super_grid[subfig_specs['analysis']]) + analysis_grid = analysis_subfig.add_gridspec(**analysis_grid_kwargs) + analysis_ax = analysis_subfig.add_subplot(analysis_grid[0, 0]) + analysis_ax.set_xlim(noise_data['scales'].min(), noise_data['scales'].max()) + analysis_ax.xaxis.set_major_locator(plt.MultipleLocator(xloc['analysis'])) + xlabel(analysis_ax, xlabels['analysis'], **xlab_analysis_kwargs, + transform=analysis_subfig.transSubfigure) + # analysis_ax.set_yscale('log') + ylabel(analysis_ax, ylabels['analysis'], **ylab_analysis_kwargs, + transform=analysis_subfig.transSubfigure) + analysis_subfig.text(s='c', **letter_analysis_kwargs) + + # Plot pure-song kernel response snippets: + plot_snippets(pure_axes[snip_specs['conv']], t_full, pure_data['conv'], + ymin=0, c=colors['conv'], lw=lw_snippets) + + # Plot pure-song binary snippets: + plot_bi_snippets(pure_axes[snip_specs['bi']], t_full, pure_data['bi'], + color=colors['bi'], lw=0) + + # Plot pure-song feature snippets: + plot_snippets(pure_axes[snip_specs['feat']], t_full, pure_data['feat'], + c=colors['feat'], lw=lw_snippets) + + # Indicate time scale: + time_bar(pure_axes[snip_specs['conv']][0], bar_time, **bar_kwargs) + + # Plot noise-song kernel response snippets: + plot_snippets(noise_axes[snip_specs['conv']], t_full, noise_data['conv'], + ymin=0, c=colors['conv'], lw=lw_snippets) + + # Plot noise-song binary snippets: + plot_bi_snippets(noise_axes[snip_specs['bi']], t_full, noise_data['bi'], + color=colors['bi'], lw=0) + + # Plot noise-song feature snippets: + plot_snippets(noise_axes[snip_specs['feat']], t_full, noise_data['feat'], + c=colors['feat'], lw=lw_snippets) + + # Indicate time scale: + time_bar(noise_axes[snip_specs['conv']][0], bar_time, **bar_kwargs) + + # Plot noise-song SD ratios (limited): + analysis_ax.plot(noise_data['scales'], noise_data['measure_conv'], + c=colors['conv'], lw=lw_analysis) + lower, upper = noise_data['spread_conv'] + analysis_ax.fill_between(noise_data['scales'], lower, upper, + color=colors['conv'], **spread_kwargs) + analysis_ax.plot(noise_data['scales'], noise_data['measure_feat'], + c=colors['feat'], lw=lw_analysis) + lower, upper = noise_data['spread_feat'] + analysis_ax.fill_between(noise_data['scales'], lower, upper, + color=colors['feat'], **spread_kwargs) + + if save_path is not None: + fig.savefig(save_path) + plt.show() + +print('Done.') +embed() diff --git a/python/plot_functions.py b/python/plot_functions.py index 6d15213..34c407f 100644 --- a/python/plot_functions.py +++ b/python/plot_functions.py @@ -69,14 +69,22 @@ def ylimits(signal, ax=None, minval=None, maxval=None, pad=0.05): return ax.set_ylim(limits) return limits -def xlabel(ax, label, y=-0.1, fontsize=20, **kwargs): +def xlabel(ax, label, x=None, y=-0.1, fontsize=20, transform=None, **kwargs): ax.set_xlabel(label, fontsize=fontsize, **kwargs) - ax.xaxis.set_label_coords(0.5, y) + if x is None: + x = 0.5 + if transform is not None: + x = (ax.transAxes + transform.inverted()).transform((x, 0))[0] + ax.xaxis.set_label_coords(x, y, transform=transform) return None -def ylabel(ax, label, x=-0.2, fontsize=20, **kwargs): +def ylabel(ax, label, x=-0.2, y=None, fontsize=20, transform=None, **kwargs): ax.set_ylabel(label, fontsize=fontsize, **kwargs) - ax.yaxis.set_label_coords(x, 0.5) + if y is None: + y = 0.5 + if transform is not None: + y = (ax.transAxes + transform.inverted()).transform((0, y))[1] + ax.yaxis.set_label_coords(x, y, transform=transform) return None def super_xlabel(label, fig, high_ax, low_ax, y=0.005, **kwargs): @@ -136,3 +144,13 @@ def reorder_traces(handles, signal, zlow=2, zhigh=2.5): handles[ind].set_zorder(z) return None +def strip_zeros(num, right_digits=5): + if isinstance(num, int): + return num + num = f'{num:.{right_digits}f}' + left, right = num.split('.') + right = right.rstrip('0') + if right: + return f'{left}.{right}' + return left + diff --git a/python/plotstyle_plt.py b/python/plotstyle_plt.py index 09d0e02..80c465c 100644 --- a/python/plotstyle_plt.py +++ b/python/plotstyle_plt.py @@ -13,7 +13,7 @@ mpl.rcParams['font.size'] = 14 mpl.rcParams['figure.titlesize'] = 15 mpl.rcParams['figure.labelsize'] = 14 mpl.rcParams['axes.labelsize'] = 14 -mpl.rcParams['axes.titlesize'] = 14 +mpl.rcParams['axes.titlesize'] = 16 mpl.rcParams['xtick.labelsize'] = 13 mpl.rcParams['ytick.labelsize'] = 13 mpl.rcParams['legend.fontsize'] = 14 diff --git a/python/save_inv_data_log-hp.py b/python/save_inv_data_log-hp.py index e4244ff..0fc42a5 100644 --- a/python/save_inv_data_log-hp.py +++ b/python/save_inv_data_log-hp.py @@ -1,7 +1,5 @@ -import plotstyle_plt import glob import numpy as np -import matplotlib.pyplot as plt from thunderhopper.modeltools import load_data, save_data from thunderhopper.filetools import crop_paths from thunderhopper.filters import decibel, sosfilter @@ -14,111 +12,73 @@ data_paths = glob.glob(f'../data/processed/{target}*.npz') save_path = '../data/inv/log_hp/' # ANALYSIS SETTINGS: -scales = np.arange(0, 10.1, 0.1) -save_scales = np.array([0, 0.5, 1, 2, 5, 10]) -floor_percents = dict(song=100, noise=99) +add_noise = False single_db_ref = True -plot_redundant = False +# find_saturation = add_noise and False +example_scales = np.array([0, 0.1, 1, 10, 100, 200]) +scales = np.geomspace(0.1, 1000, 100) +if not add_noise: + example_scales = example_scales[example_scales > 0] +scales = np.unique(np.concatenate((scales, example_scales))) +# if find_saturation: +# scales = np.append(scales, 10e10) # EXECUTION: for data_path, name in zip(data_paths, crop_paths(data_paths)): print(f'Processing {name}') - # Load song envelope: + # Get normalized song envelope: data, config = load_data(data_path, files='env') song, rate = data['env'], config['env_rate'] - t_full = np.arange(song.shape[0]) / rate - - # Generate noise envelope: - rng = np.random.default_rng() - noise = rng.normal(size=song.shape) - noise = extract_env(noise, rate, config=config) - - # Normalize each: song /= song.std() - noise /= noise.std() - # Mix song component and noise component: - scaled = song[:, None] * scales[None, :] - mix = scaled + noise[:, None] + # Rescale song component: + mix = song[:, None] * scales[None, :] - # Find noise floor (experimental): - song_percent = np.percentile(scaled, floor_percents['song'], axis=0) - noise_percent = np.percentile(noise, floor_percents['noise']) - floor_scale = scales[np.nonzero(song_percent <= noise_percent)[0][-1]] + if add_noise: + # Add normalized noise envelope: + rng = np.random.default_rng() + noise = rng.normal(size=song.shape) + noise = extract_env(noise, rate, config=config) + noise /= noise.std() + mix += noise[:, None] # Process mixture: mix_log = decibel(mix, axis=None if single_db_ref else 0) mix_inv = sosfilter(mix_log, rate, config['inv_fcut'], 'hp', padtype='constant', padlen=config['padlen']) - # Get variances per stage: - var_env = mix.var(axis=0) - var_log = mix_log.var(axis=0) - var_inv = mix_inv.var(axis=0) + # Get "intensity measure" per stage: + measure_env = mix.std(axis=0) + measure_log = mix_log.std(axis=0) + measure_inv = mix_inv.std(axis=0) - # Get SNRs against pure noise per stage: - base_ind = np.nonzero(scales == 0)[0][0] - snr_env = var_env / var_env[base_ind] - snr_log = var_log / var_log[base_ind] - snr_inv = var_inv / var_inv[base_ind] - - if plot_redundant: - # Normalize SNRs: - norm_snr_env = snr_env / snr_env.max() - norm_snr_log = snr_log / snr_log.max() - norm_snr_inv = snr_inv / snr_inv.max() - - # Get SNR gain against env: - gain_log = snr_log / snr_env - gain_inv = snr_inv / snr_env - - # Plot results: - fig, axes = plt.subplots(6, 1, sharex=True, layout='constrained') - - axes[0].set_title('variance') - axes[0].plot(scales, var_env) - axes[0].plot(scales, var_log) - axes[0].plot(scales, var_inv) - - axes[1].set_title('normalized variance') - axes[1].plot(scales, var_env / var_env.max()) - axes[1].plot(scales, var_log / var_log.max()) - axes[1].plot(scales, var_inv / var_inv.max()) - - axes[2].set_title('SNR') - axes[2].plot(scales, snr_env) - axes[2].plot(scales, snr_log) - axes[2].plot(scales, snr_inv) - - axes[3].set_title('normalized SNR') - axes[3].plot(scales, norm_snr_env) - axes[3].plot(scales, norm_snr_log) - axes[3].plot(scales, norm_snr_inv) - - axes[4].set_title('gain (absolute SNR)') - axes[4].plot(scales, gain_log) - axes[4].plot(scales, gain_inv) - - axes[5].set_title('gain (normalized SNR)') - axes[5].plot(scales, norm_snr_log / norm_snr_env) - axes[5].plot(scales, norm_snr_inv / norm_snr_env) - plt.show() + # # Find saturation level: + # if find_saturation: + # limit = measure_inv[-1] + # scales = scales[:-1] + # measure_env = measure_env[:-1] + # measure_log = measure_log[:-1] + # measure_inv = measure_inv[:-1] # Save analysis results: - save_inds = np.isin(scales, save_scales) + save_inds = np.nonzero(np.isin(scales, example_scales))[0] if save_path is not None: data = dict( scales=scales, - plot_scales=scales[save_inds], - floor_scale=floor_scale, + example_scales=example_scales, env=mix[:, save_inds], log=mix_log[:, save_inds], inv=mix_inv[:, save_inds], - snr_env=snr_env, - snr_log=snr_log, - snr_inv=snr_inv, + measure_env=measure_env, + measure_log=measure_log, + measure_inv=measure_inv, ) - save_data(save_path + name, data, config, overwrite=True) + # if find_saturation: + # data['limit'] = limit + file_name = save_path + name + if add_noise: + file_name += '_noise' + save_data(file_name, data, config, overwrite=True) print('Done.') embed() diff --git a/python/save_inv_data_thresh-lp.py b/python/save_inv_data_thresh-lp.py new file mode 100644 index 0000000..7c8d83f --- /dev/null +++ b/python/save_inv_data_thresh-lp.py @@ -0,0 +1,110 @@ +import glob +import numpy as np +from thunderhopper.modeltools import load_data, save_data +from thunderhopper.filetools import crop_paths +from thunderhopper.filters import sosfilter +from IPython import embed + +# GENERAL SETTINGS: +target = 'Omocestus_rufipes' +data_paths = glob.glob(f'../data/processed/{target}*.npz') +save_path = '../data/inv/thresh_lp/' + +# ANALYSIS SETTINGS: +add_noise = False +threshold = 0.5 +example_scales = np.array([threshold, 0.6, 1, 10, 50, 100]) +scales = np.linspace(threshold + 0.1, 100, 100) +if not add_noise: + example_scales = example_scales[example_scales > threshold] +scales = np.unique(np.concatenate((scales, example_scales))) + +# EXECUTION: +for data_path, name in zip(data_paths, crop_paths(data_paths)): + print(f'Processing {name}') + + # Get normalized pure-song kernel responses: + data, config = load_data(data_path, files='conv') + song, rate = data['conv'], data['conv_rate'] + song /= song.std(axis=0) + + # Prepare kernel-specific thresholds: + threshold *= song.max(axis=0, keepdims=True) + + if add_noise: + # Get normalized noise: + rng = np.random.default_rng() + noise = rng.normal(size=(song.shape[0], 1)) + noise /= noise.std() + + # Prepare snippet storage: + shape = song.shape + (example_scales.size,) + conv = np.zeros(shape, dtype=float) + bi = np.zeros(shape, dtype=float) + feat = np.zeros(shape, dtype=float) + + # Prepare measure storage: + shape = (scales.size, song.shape[1]) + measure_conv = np.zeros(shape, dtype=float) + measure_feat = np.zeros(shape, dtype=float) + + # Execute piecewise: + for i, scale in enumerate(scales): + print('Simulating scale ', scale) + + # Rescale song component: + scaled_conv = song * scale + if add_noise: + # Add noise: + scaled_conv += noise + + # Process mixture: + scaled_bi = (scaled_conv > threshold).astype(float) + scaled_feat = sosfilter(scaled_bi, rate, config['feat_fcut'], 'lp', + padtype='fixed', padlen=config['padlen']) + + # Log snippet data: + if scale in example_scales: + scale_ind = np.nonzero(example_scales == scale)[0][0] + conv[:, :, scale_ind] = scaled_conv + bi[:, :, scale_ind] = scaled_bi + feat[:, :, scale_ind] = scaled_feat + + # Get "intensity measure" per stage: + measure_conv[i] = scaled_conv.std(axis=0) + measure_feat[i] = scaled_feat.mean(axis=0) + + # Relate to smallest scale: + base_ind = np.argmin(scales) + measure_conv /= measure_conv[base_ind, :] + measure_feat /= measure_feat[base_ind, :] + + # Condense measures across kernels: + spread_conv = np.zeros((2, scales.size)) + spread_conv[0] = np.percentile(measure_conv, 25, axis=1) + spread_conv[1] = np.percentile(measure_conv, 75, axis=1) + measure_conv = np.median(measure_conv, axis=1) + spread_feat = np.zeros((2, scales.size)) + spread_feat[0] = np.percentile(measure_feat, 25, axis=1) + spread_feat[1] = np.percentile(measure_feat, 75, axis=1) + measure_feat = np.median(measure_feat, axis=1) + + # Save analysis results: + if save_path is not None: + data = dict( + scales=scales, + example_scales=example_scales, + conv=conv, + bi=bi, + feat=feat, + measure_conv=measure_conv, + spread_conv=spread_conv, + measure_feat=measure_feat, + spread_feat=spread_feat, + ) + file_name = save_path + name + if add_noise: + file_name += '_noise' + save_data(file_name, data, config, overwrite=True) +print('Done.') +embed()