merge master

This commit is contained in:
sprause 2023-01-23 09:58:48 +01:00
commit e19ddcb391
19 changed files with 3859 additions and 526 deletions

312
README.md
View File

@ -1,64 +1,248 @@
# Chirp detection - GP2023 <!-- Improved compatibility of back to top link: See: https://github.com/othneildrew/Best-README-Template/pull/73 -->
## Git-Repository and commands <a name="readme-top"></a>
<!--
- Go to the [Bendalab Git-Server](https://whale.am28.uni-tuebingen.de/git/) (https://whale.am28.uni-tuebingen.de/git/) *** Thanks for checking out the Best-README-Template. If you have a suggestion
- Create your own account (and tell me ;D) *** that would make this better, please fork the repo and create a pull request
* I'll invite you the repository *** or simply open an issue with the tag "enhancement".
- Clone the repository *** Don't forget to give the project a star!
- *** Thanks again! Now go create something AMAZING! :D
```sh -->
git clone https://whale.am28.uni-tuebingen.de/git/raab/GP2023_chirp_detection.git
```
## Basic git commands <!-- PROJECT SHIELDS -->
<!--
- pull changes in git *** I'm using markdown "reference style" links for readability.
```shell *** Reference links are enclosed in brackets [ ] instead of parentheses ( ).
git pull origin <branch> *** See the bottom of this document for the declaration of the reference variables
``` *** for contributors-url, forks-url, etc. This is an optional, concise syntax you may use.
- commit chances *** https://www.markdownguide.org/basic-syntax/#reference-style-links
```shell -->
git commit -m '<explaination>' file # commit one file <!-- [![Contributors][contributors-shield]][contributors-url] -->
git commit -a -m '<explaination>' # commit all files <!-- [![Forks][forks-shield]][forks-url] -->
``` <!-- [![Stargazers][stars-shield]][stars-url] -->
- push commits <!-- [![Issues][issues-shield]][issues-url] -->
```shell <!-- [![MIT License][license-shield]][license-url] -->
git push origin <branch> <!-- [![LinkedIn][linkedin-shield]][linkedin-url] -->
```
## Branches
Use branches to work on specific topics (e.g. 'algorithm', 'analysis', 'writing', ore even more specific ones) and merge <!-- PROJECT LOGO -->
them into Master-Branch when it works are up to your expectations. <br />
<div align="center">
The "master" branch should always contain a working/correct version of your project. <a href="https://github.com/github_username/repo_name">
<img src="assets/logo.png" alt="Logo" width="150" height="100">
- Create/change into branches </a>
```shell
# list all branches (highlight active branch) <h3 align="center">chirpdetector</h3>
git banch -a
# switch into existing <p align="center">
git checkout <existing branch> An algorithm to detect the chirps of weakly electric fish.
# switch into new branch <br />
git checkout master <a href="https://github.com/github_username/repo_name"><strong>Explore the docs »</strong></a>
git checkout -b <new branch> <br />
``` <br />
<a href="https://github.com/github_username/repo_name">View Demo</a>
·
- Re-merging with master branch <a href="https://github.com/github_username/repo_name/issues">Report Bug</a>
1) get current version of master and implement it into branch ·
```shell <a href="https://github.com/github_username/repo_name/issues">Request Feature</a>
git checkout master </p>
git pull origin master </div>
git checkout <branch>
git rebase master
```
This resets you branch to the fork-point, executes all commits of the current master before adding the commits of you <!-- TABLE OF CONTENTS -->
branch. You may have to resolve potential conflicts. Afterwards commit the corrected version and push it to your branch. <details>
<summary>Table of Contents</summary>
2) Update master branch master <ol>
- correct way: Create <li>
```shell <a href="#about-the-project">About The Project</a>
git checkout master <ul>
git merge <branch> <li><a href="#built-with">Built With</a></li>
git push origin master </ul>
``` </li>
<li>
<a href="#getting-started">Getting Started</a>
<ul>
<li><a href="#prerequisites">Prerequisites</a></li>
<li><a href="#installation">Installation</a></li>
</ul>
</li>
<li><a href="#usage">Usage</a></li>
<li><a href="#roadmap">Roadmap</a></li>
<li><a href="#contributing">Contributing</a></li>
<li><a href="#license">License</a></li>
<li><a href="#contact">Contact</a></li>
<li><a href="#acknowledgments">Acknowledgments</a></li>
</ol>
</details>
<!-- ABOUT THE PROJECT -->
## About The Project
[![Product Name Screen Shot][product-screenshot]](https://example.com)
Here's a blank template to get started: To avoid retyping too much info. Do a search and replace with your text editor for the following: `github_username`, `repo_name`, `twitter_handle`, `linkedin_username`, `email_client`, `email`, `project_title`, `project_description`
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- ### Built With -->
<!-- * [![Next][Next.js]][Next-url] -->
<!-- * [![React][React.js]][React-url] -->
<!-- * [![Vue][Vue.js]][Vue-url] -->
<!-- * [![Angular][Angular.io]][Angular-url] -->
<!-- * [![Svelte][Svelte.dev]][Svelte-url] -->
<!-- * [![Laravel][Laravel.com]][Laravel-url] -->
<!-- * [![Bootstrap][Bootstrap.com]][Bootstrap-url] -->
<!-- * [![JQuery][JQuery.com]][JQuery-url] -->
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- GETTING STARTED -->
## Getting Started
This is an example of how you may give instructions on setting up your project locally.
To get a local copy up and running follow these simple example steps.
<!-- ### Prerequisites -->
<!-- This is an example of how to list things you need to use the software and how to install them. -->
<!-- * npm -->
<!-- ```sh -->
<!-- npm install npm@latest -g -->
<!-- ``` -->
### Installation
1. Get a free API Key at [https://example.com](https://example.com)
2. Clone the repo
```sh
git clone https://github.com/github_username/repo_name.git
```
3. Install NPM packages
```sh
npm install
```
4. Enter your API in `config.js`
```js
const API_KEY = 'ENTER YOUR API';
```
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- USAGE EXAMPLES -->
## Usage
Use this space to show useful examples of how a project can be used. Additional screenshots, code examples and demos work well in this space. You may also link to more resources.
_For more examples, please refer to the [Documentation](https://example.com)_
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- ROADMAP -->
## Roadmap
- [ ] Feature 1
- [ ] Feature 2
- [ ] Feature 3
- [ ] Nested Feature
See the [open issues](https://github.com/github_username/repo_name/issues) for a full list of proposed features (and known issues).
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- <!-1- CONTRIBUTING -1-> -->
<!-- ## Contributing -->
<!-- Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. -->
<!-- If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". -->
<!-- Don't forget to give the project a star! Thanks again! -->
<!-- 1. Fork the Project -->
<!-- 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) -->
<!-- 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) -->
<!-- 4. Push to the Branch (`git push origin feature/AmazingFeature`) -->
<!-- 5. Open a Pull Request -->
<!-- <p align="right">(<a href="#readme-top">back to top</a>)</p> -->
<!-- <!-1- LICENSE -1-> -->
<!-- ## License -->
<!-- Distributed under the MIT License. See `LICENSE.txt` for more information. -->
<!-- <p align="right">(<a href="#readme-top">back to top</a>)</p> -->
<!-- CONTACT -->
## Contact
Your Name - [@twitter_handle](https://twitter.com/twitter_handle) - email@email_client.com
Project Link: [https://github.com/github_username/repo_name](https://github.com/github_username/repo_name)
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- ACKNOWLEDGMENTS -->
## Acknowledgments
* []()
* []()
* []()
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- MARKDOWN LINKS & IMAGES -->
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
[contributors-shield]: https://img.shields.io/github/contributors/github_username/repo_name.svg?style=for-the-badge
[contributors-url]: https://github.com/github_username/repo_name/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/github_username/repo_name.svg?style=for-the-badge
[forks-url]: https://github.com/github_username/repo_name/network/members
[stars-shield]: https://img.shields.io/github/stars/github_username/repo_name.svg?style=for-the-badge
[stars-url]: https://github.com/github_username/repo_name/stargazers
[issues-shield]: https://img.shields.io/github/issues/github_username/repo_name.svg?style=for-the-badge
[issues-url]: https://github.com/github_username/repo_name/issues
[license-shield]: https://img.shields.io/github/license/github_username/repo_name.svg?style=for-the-badge
[license-url]: https://github.com/github_username/repo_name/blob/master/LICENSE.txt
[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
[linkedin-url]: https://linkedin.com/in/linkedin_username
[product-screenshot]: images/screenshot.png
[Next.js]: https://img.shields.io/badge/next.js-000000?style=for-the-badge&logo=nextdotjs&logoColor=white
[Next-url]: https://nextjs.org/
[React.js]: https://img.shields.io/badge/React-20232A?style=for-the-badge&logo=react&logoColor=61DAFB
[React-url]: https://reactjs.org/
[Vue.js]: https://img.shields.io/badge/Vue.js-35495E?style=for-the-badge&logo=vuedotjs&logoColor=4FC08D
[Vue-url]: https://vuejs.org/
[Angular.io]: https://img.shields.io/badge/Angular-DD0031?style=for-the-badge&logo=angular&logoColor=white
[Angular-url]: https://angular.io/
[Svelte.dev]: https://img.shields.io/badge/Svelte-4A4A55?style=for-the-badge&logo=svelte&logoColor=FF3E00
[Svelte-url]: https://svelte.dev/
[Laravel.com]: https://img.shields.io/badge/Laravel-FF2D20?style=for-the-badge&logo=laravel&logoColor=white
[Laravel-url]: https://laravel.com
[Bootstrap.com]: https://img.shields.io/badge/Bootstrap-563D7C?style=for-the-badge&logo=bootstrap&logoColor=white
[Bootstrap-url]: https://getbootstrap.com
[JQuery.com]: https://img.shields.io/badge/jQuery-0769AD?style=for-the-badge&logo=jquery&logoColor=white
[JQuery-url]: https://jquery.com

64
README1.md Normal file
View File

@ -0,0 +1,64 @@
# Chirp detection - GP2023
## Git-Repository and commands
- Go to the [Bendalab Git-Server](https://whale.am28.uni-tuebingen.de/git/) (https://whale.am28.uni-tuebingen.de/git/)
- Create your own account (and tell me ;D)
* I'll invite you the repository
- Clone the repository
-
```sh
git clone https://whale.am28.uni-tuebingen.de/git/raab/GP2023_chirp_detection.git
```
## Basic git commands
- pull changes in git
```shell
git pull origin <branch>
```
- commit chances
```shell
git commit -m '<explaination>' file # commit one file
git commit -a -m '<explaination>' # commit all files
```
- push commits
```shell
git push origin <branch>
```
## Branches
Use branches to work on specific topics (e.g. 'algorithm', 'analysis', 'writing', ore even more specific ones) and merge
them into Master-Branch when it works are up to your expectations.
The "master" branch should always contain a working/correct version of your project.
- Create/change into branches
```shell
# list all branches (highlight active branch)
git banch -a
# switch into existing
git checkout <existing branch>
# switch into new branch
git checkout master
git checkout -b <new branch>
```
- Re-merging with master branch
1) get current version of master and implement it into branch
```shell
git checkout master
git pull origin master
git checkout <branch>
git rebase master
```
This resets you branch to the fork-point, executes all commits of the current master before adding the commits of you
branch. You may have to resolve potential conflicts. Afterwards commit the corrected version and push it to your branch.
2) Update master branch master
- correct way: Create
```shell
git checkout master
git merge <branch>
git push origin master
```

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

1184
assets/logo.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 84 KiB

View File

@ -1,4 +1,5 @@
import os import os
import os
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
@ -268,4 +269,5 @@ def main(datapath: str):
if __name__ == '__main__': if __name__ == '__main__':
# Path to the data # Path to the data
datapath = '../data/mount_data/2020-05-13-10_00/' datapath = '../data/mount_data/2020-05-13-10_00/'
datapath = '../data/mount_data/2020-05-13-10_00/'
main(datapath) main(datapath)

1095
code/chirpdetection.py Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +1,46 @@
# directory setup
dataroot: "../data/" dataroot: "../data/"
outputdir: "../output/" outputdir: "../output/"
# Duration and overlap of the analysis window in seconds # Duration and overlap of the analysis window in seconds
window: 5 window: 10
overlap: 1 overlap: 1
edge: 0.25 edge: 0.25
# Number of electrodes to go over # Number of electrodes to go over
number_electrodes: 3 number_electrodes: 3
minimum_electrodes: 2
# Boundary for search frequency in Hz # Search window bandwidth and minimal baseline bandwidth
search_boundary: 100 minimal_bandwidth: 20
# Cutoff frequency for envelope estimation by lowpass filter # Instantaneous frequency smoothing usint a gaussian kernel of this width
envelope_cutoff: 25 baseline_frequency_smoothing: 5
# Cutoff frequency for envelope highpass filter # Baseline processing parameters
envelope_highpass_cutoff: 3 baseline_envelope_cutoff: 25
baseline_envelope_bandpass_lowf: 4
baseline_envelope_bandpass_highf: 100
baseline_envelope_envelope_cutoff: 4
# Cutoff frequency for envelope of envelope # search envelope processing parameters
envelope_envelope_cutoff: 5 search_envelope_cutoff: 5
# Instantaneous frequency bandpass filter cutoff frequencies # Instantaneous frequency bandpass filter cutoff frequencies
instantaneous_lowf: 15 baseline_frequency_highpass_cutoff: 0.000005
instantaneous_highf: 8000 baseline_frequency_envelope_cutoff: 0.000005
# Baseline envelope peak detection parameters # peak detecion parameters
baseline_prominence_percentile: 90 prominence: 0.005
# Search envelope peak detection parameters
search_prominence_percentile: 90
# Instantaneous frequency peak detection parameters
instantaneous_prominence_percentile: 90
# search freq parameter # search freq parameter
search_df_lower: 25 search_df_lower: 20
search_df_upper: 100 search_df_upper: 100
search_res: 1 search_res: 1
search_freq_percentiles: search_bandwidth: 10
- 5
- 95
default_search_freq: 50 default_search_freq: 50
# Classify events as chirps if they are less than this time apart
chirp_window_threshold: 0.05 chirp_window_threshold: 0.05

View File

@ -1,5 +1,78 @@
import numpy as np import numpy as np
from typing import List, Any from typing import List, Any
from scipy.ndimage import gaussian_filter1d
from scipy.stats import gamma, norm
def scale01(data):
"""
Normalize data to [0, 1]
Parameters
----------
data : np.ndarray
Data to normalize.
Returns
-------
np.ndarray
Normalized data.
"""
return (2*((data - np.min(data)) / (np.max(data) - np.min(data)))) - 1
def instantaneous_frequency(
signal: np.ndarray,
samplerate: int,
smoothing_window: int,
) -> tuple[np.ndarray, np.ndarray]:
"""
Compute the instantaneous frequency of a signal that is approximately
sinusoidal and symmetric around 0.
Parameters
----------
signal : np.ndarray
Signal to compute the instantaneous frequency from.
samplerate : int
Samplerate of the signal.
smoothing_window : int
Window size for the gaussian filter.
Returns
-------
tuple[np.ndarray, np.ndarray]
"""
# calculate instantaneous frequency with zero crossings
roll_signal = np.roll(signal, shift=1)
time_signal = np.arange(len(signal)) / samplerate
period_index = np.arange(len(signal))[(roll_signal < 0) & (signal >= 0)][
1:-1
]
upper_bound = np.abs(signal[period_index])
lower_bound = np.abs(signal[period_index - 1])
upper_time = np.abs(time_signal[period_index])
lower_time = np.abs(time_signal[period_index - 1])
# create ratio
lower_ratio = lower_bound / (lower_bound + upper_bound)
# appy to time delta
time_delta = upper_time - lower_time
true_zero = lower_time + lower_ratio * time_delta
# create new time array
instantaneous_frequency_time = true_zero[:-1] + 0.5 * np.diff(true_zero)
# compute frequency
instantaneous_frequency = gaussian_filter1d(
1 / np.diff(true_zero), smoothing_window
)
return instantaneous_frequency_time, instantaneous_frequency
def purge_duplicates( def purge_duplicates(
@ -64,7 +137,7 @@ def purge_duplicates(
def group_timestamps( def group_timestamps(
sublists: List[List[float]], n: int, threshold: float sublists: List[List[float]], at_least_in: int, difference_threshold: float
) -> List[float]: ) -> List[float]:
""" """
Groups timestamps that are less than `threshold` milliseconds apart from Groups timestamps that are less than `threshold` milliseconds apart from
@ -100,7 +173,7 @@ def group_timestamps(
# Group timestamps that are less than threshold milliseconds apart # Group timestamps that are less than threshold milliseconds apart
for i in range(1, len(timestamps)): for i in range(1, len(timestamps)):
if timestamps[i] - timestamps[i - 1] < threshold: if timestamps[i] - timestamps[i - 1] < difference_threshold:
current_group.append(timestamps[i]) current_group.append(timestamps[i])
else: else:
groups.append(current_group) groups.append(current_group)
@ -111,7 +184,7 @@ def group_timestamps(
# Retain only groups that contain at least n timestamps # Retain only groups that contain at least n timestamps
final_groups = [] final_groups = []
for group in groups: for group in groups:
if len(group) >= n: if len(group) >= at_least_in:
final_groups.append(group) final_groups.append(group)
# Calculate the mean of each group # Calculate the mean of each group
@ -137,6 +210,117 @@ def flatten(list: List[List[Any]]) -> List:
return [item for sublist in list for item in sublist] return [item for sublist in list for item in sublist]
def causal_kde1d(spikes, time, width, shape=2):
"""
causalkde computes a kernel density estimate using a causal kernel (i.e. exponential or gamma distribution).
A shape of 1 turns the gamma distribution into an exponential.
Parameters
----------
spikes : array-like
spike times
time : array-like
sampling time
width : float
kernel width
shape : int, optional
shape of gamma distribution, by default 1
Returns
-------
rate : array-like
instantaneous firing rate
"""
# compute dt
dt = time[1] - time[0]
# time on which to compute kernel:
tmax = 10 * width
# kernel not wider than time
if 2 * tmax > time[-1] - time[0]:
tmax = 0.5 * (time[-1] - time[0])
# kernel time
ktime = np.arange(-tmax, tmax, dt)
# gamma kernel centered in ktime:
kernel = gamma.pdf(
x=ktime,
a=shape,
loc=0,
scale=width,
)
# indices of spikes in time array:
indices = np.asarray((spikes - time[0]) / dt, dtype=int)
# binary spike train:
brate = np.zeros(len(time))
brate[indices[(indices >= 0) & (indices < len(time))]] = 1.0
# convolution with kernel:
rate = np.convolve(brate, kernel, mode="same")
return rate
def acausal_kde1d(spikes, time, width):
"""
causalkde computes a kernel density estimate using a causal kernel (i.e. exponential or gamma distribution).
A shape of 1 turns the gamma distribution into an exponential.
Parameters
----------
spikes : array-like
spike times
time : array-like
sampling time
width : float
kernel width
shape : int, optional
shape of gamma distribution, by default 1
Returns
-------
rate : array-like
instantaneous firing rate
"""
# compute dt
dt = time[1] - time[0]
# time on which to compute kernel:
tmax = 10 * width
# kernel not wider than time
if 2 * tmax > time[-1] - time[0]:
tmax = 0.5 * (time[-1] - time[0])
# kernel time
ktime = np.arange(-tmax, tmax, dt)
# gamma kernel centered in ktime:
kernel = norm.pdf(
x=ktime,
loc=0,
scale=width,
)
# indices of spikes in time array:
indices = np.asarray((spikes - time[0]) / dt, dtype=int)
# binary spike train:
brate = np.zeros(len(time))
brate[indices[(indices >= 0) & (indices < len(time))]] = 1.0
# convolution with kernel:
rate = np.convolve(brate, kernel, mode="same")
return rate
if __name__ == "__main__": if __name__ == "__main__":
timestamps = [ timestamps = [

View File

@ -3,8 +3,8 @@ import numpy as np
def bandpass_filter( def bandpass_filter(
data: np.ndarray, signal: np.ndarray,
rate: float, samplerate: float,
lowf: float, lowf: float,
highf: float, highf: float,
) -> np.ndarray: ) -> np.ndarray:
@ -12,7 +12,7 @@ def bandpass_filter(
Parameters Parameters
---------- ----------
data : np.ndarray signal : np.ndarray
The data to be filtered The data to be filtered
rate : float rate : float
The sampling rate The sampling rate
@ -26,21 +26,22 @@ def bandpass_filter(
np.ndarray np.ndarray
The filtered data The filtered data
""" """
sos = butter(2, (lowf, highf), "bandpass", fs=rate, output="sos") sos = butter(2, (lowf, highf), "bandpass", fs=samplerate, output="sos")
fdata = sosfiltfilt(sos, data) filtered_signal = sosfiltfilt(sos, signal)
return fdata
return filtered_signal
def highpass_filter( def highpass_filter(
data: np.ndarray, signal: np.ndarray,
rate: float, samplerate: float,
cutoff: float, cutoff: float,
) -> np.ndarray: ) -> np.ndarray:
"""Highpass filter a signal. """Highpass filter a signal.
Parameters Parameters
---------- ----------
data : np.ndarray signal : np.ndarray
The data to be filtered The data to be filtered
rate : float rate : float
The sampling rate The sampling rate
@ -52,14 +53,15 @@ def highpass_filter(
np.ndarray np.ndarray
The filtered data The filtered data
""" """
sos = butter(2, cutoff, "highpass", fs=rate, output="sos") sos = butter(2, cutoff, "highpass", fs=samplerate, output="sos")
fdata = sosfiltfilt(sos, data) filtered_signal = sosfiltfilt(sos, signal)
return fdata
return filtered_signal
def lowpass_filter( def lowpass_filter(
data: np.ndarray, signal: np.ndarray,
rate: float, samplerate: float,
cutoff: float cutoff: float
) -> np.ndarray: ) -> np.ndarray:
"""Lowpass filter a signal. """Lowpass filter a signal.
@ -78,21 +80,25 @@ def lowpass_filter(
np.ndarray np.ndarray
The filtered data The filtered data
""" """
sos = butter(2, cutoff, "lowpass", fs=rate, output="sos") sos = butter(2, cutoff, "lowpass", fs=samplerate, output="sos")
fdata = sosfiltfilt(sos, data) filtered_signal = sosfiltfilt(sos, signal)
return fdata
return filtered_signal
def envelope(data: np.ndarray, rate: float, freq: float) -> np.ndarray:
def envelope(signal: np.ndarray,
samplerate: float,
cutoff_frequency: float
) -> np.ndarray:
"""Calculate the envelope of a signal using a lowpass filter. """Calculate the envelope of a signal using a lowpass filter.
Parameters Parameters
---------- ----------
data : np.ndarray signal : np.ndarray
The signal to calculate the envelope of The signal to calculate the envelope of
rate : float samplingrate : float
The sampling rate of the signal The sampling rate of the signal
freq : float cutoff_frequency : float
The cutoff frequency of the lowpass filter The cutoff frequency of the lowpass filter
Returns Returns
@ -100,6 +106,7 @@ def envelope(data: np.ndarray, rate: float, freq: float) -> np.ndarray:
np.ndarray np.ndarray
The envelope of the signal The envelope of the signal
""" """
sos = butter(2, freq, "lowpass", fs=rate, output="sos") sos = butter(2, cutoff_frequency, "lowpass", fs=samplerate, output="sos")
envelope = np.sqrt(2) * sosfiltfilt(sos, np.abs(data)) envelope = np.sqrt(2) * sosfiltfilt(sos, np.abs(signal))
return envelope return envelope

View File

@ -30,10 +30,14 @@ def PlotStyle() -> None:
purple = "#cba6f7" purple = "#cba6f7"
pink = "#f5c2e7" pink = "#f5c2e7"
lavender = "#b4befe" lavender = "#b4befe"
gblue1 = "#8cb8ff"
gblue2 = "#7cdcdc"
gblue3 = "#82e896"
@classmethod @classmethod
def lims(cls, track1, track2): def lims(cls, track1, track2):
"""Helper function to get frequency y axis limits from two fundamental frequency tracks. """Helper function to get frequency y axis limits from two
fundamental frequency tracks.
Args: Args:
track1 (array): First track track1 (array): First track
@ -91,6 +95,16 @@ def PlotStyle() -> None:
ax.tick_params(left=False, labelleft=False) ax.tick_params(left=False, labelleft=False)
ax.patch.set_visible(False) ax.patch.set_visible(False)
@classmethod
def hide_xax(cls, ax):
ax.xaxis.set_visible(False)
ax.spines["bottom"].set_visible(False)
@classmethod
def hide_yax(cls, ax):
ax.yaxis.set_visible(False)
ax.spines["left"].set_visible(False)
@classmethod @classmethod
def set_boxplot_color(cls, bp, color): def set_boxplot_color(cls, bp, color):
plt.setp(bp["boxes"], color=color) plt.setp(bp["boxes"], color=color)
@ -216,8 +230,8 @@ def PlotStyle() -> None:
plt.rc("figure", titlesize=BIGGER_SIZE) # fontsize of the figure title plt.rc("figure", titlesize=BIGGER_SIZE) # fontsize of the figure title
plt.rcParams["image.cmap"] = 'cmo.haline' plt.rcParams["image.cmap"] = 'cmo.haline'
# plt.rcParams["axes.xmargin"] = 0.1 plt.rcParams["axes.xmargin"] = 0.05
# plt.rcParams["axes.ymargin"] = 0.15 plt.rcParams["axes.ymargin"] = 0.1
plt.rcParams["axes.titlelocation"] = "left" plt.rcParams["axes.titlelocation"] = "left"
plt.rcParams["axes.titlesize"] = BIGGER_SIZE plt.rcParams["axes.titlesize"] = BIGGER_SIZE
# plt.rcParams["axes.titlepad"] = -10 # plt.rcParams["axes.titlepad"] = -10
@ -230,9 +244,9 @@ def PlotStyle() -> None:
plt.rcParams["legend.borderaxespad"] = 0.5 plt.rcParams["legend.borderaxespad"] = 0.5
plt.rcParams["legend.fancybox"] = False plt.rcParams["legend.fancybox"] = False
# specify the custom font to use # # specify the custom font to use
plt.rcParams["font.family"] = "sans-serif" # plt.rcParams["font.family"] = "sans-serif"
plt.rcParams["font.sans-serif"] = "Helvetica Now Text" # plt.rcParams["font.sans-serif"] = "Helvetica Now Text"
# dark mode modifications # dark mode modifications
plt.rcParams["boxplot.flierprops.color"] = white plt.rcParams["boxplot.flierprops.color"] = white
@ -271,7 +285,7 @@ def PlotStyle() -> None:
plt.rcParams["ytick.color"] = gray # color of the ticks plt.rcParams["ytick.color"] = gray # color of the ticks
plt.rcParams["grid.color"] = dark_gray # grid color plt.rcParams["grid.color"] = dark_gray # grid color
plt.rcParams["figure.facecolor"] = black # figure face color plt.rcParams["figure.facecolor"] = black # figure face color
plt.rcParams["figure.edgecolor"] = "#555169" # figure edge color plt.rcParams["figure.edgecolor"] = black # figure edge color
plt.rcParams["savefig.facecolor"] = black # figure face color when saving plt.rcParams["savefig.facecolor"] = black # figure face color when saving
return style return style

View File

@ -0,0 +1,121 @@
import numpy as np
import matplotlib.pyplot as plt
from thunderfish.powerspectrum import spectrogram, decibel
from modules.filehandling import LoadData
from modules.datahandling import instantaneous_frequency
from modules.filters import bandpass_filter
from modules.plotstyle import PlotStyle
ps = PlotStyle()
def main():
# Load data
datapath = "../data/2022-06-02-10_00/"
data = LoadData(datapath)
# good chirp times for data: 2022-06-02-10_00
window_start_seconds = 3 * 60 * 60 + 6 * 60 + 43.5 + 9 + 6.25
window_start_index = window_start_seconds * data.raw_rate
window_duration_seconds = 0.2
window_duration_index = window_duration_seconds * data.raw_rate
timescaler = 1000
raw = data.raw[window_start_index:window_start_index +
window_duration_index, 10]
fig, (ax1, ax2, ax3) = plt.subplots(
3, 1, figsize=(12 * ps.cm, 10*ps.cm), sharex=True, sharey=True)
# plot instantaneous frequency
filtered1 = bandpass_filter(
signal=raw, lowf=750, highf=1200, samplerate=data.raw_rate)
filtered2 = bandpass_filter(
signal=raw, lowf=550, highf=700, samplerate=data.raw_rate)
freqtime1, freq1 = instantaneous_frequency(
filtered1, data.raw_rate, smoothing_window=3)
freqtime2, freq2 = instantaneous_frequency(
filtered2, data.raw_rate, smoothing_window=3)
ax1.plot(freqtime1*timescaler, freq1, color=ps.gblue1,
lw=2, label=f"fish 1, {np.median(freq1):.0f} Hz")
ax1.plot(freqtime2*timescaler, freq2, color=ps.gblue3,
lw=2, label=f"fish 2, {np.median(freq2):.0f} Hz")
ax1.legend(bbox_to_anchor=(0, 1.02, 1, 0.2), loc="lower center",
mode="normal", borderaxespad=0, ncol=2)
ps.hide_xax(ax1)
# plot fine spectrogram
spec_power, spec_freqs, spec_times = spectrogram(
raw,
ratetime=data.raw_rate,
freq_resolution=150,
overlap_frac=0.2,
)
ylims = [300, 1200]
fmask = np.zeros(spec_freqs.shape, dtype=bool)
fmask[(spec_freqs > ylims[0]) & (spec_freqs < ylims[1])] = True
ax2.imshow(
decibel(spec_power[fmask, :]),
extent=[
spec_times[0]*timescaler,
spec_times[-1]*timescaler,
spec_freqs[fmask][0],
spec_freqs[fmask][-1],
],
aspect="auto",
origin="lower",
interpolation="gaussian",
alpha=1,
)
ps.hide_xax(ax2)
# plot coarse spectrogram
spec_power, spec_freqs, spec_times = spectrogram(
raw,
ratetime=data.raw_rate,
freq_resolution=10,
overlap_frac=0.3,
)
fmask = np.zeros(spec_freqs.shape, dtype=bool)
fmask[(spec_freqs > ylims[0]) & (spec_freqs < ylims[1])] = True
ax3.imshow(
decibel(spec_power[fmask, :]),
extent=[
spec_times[0]*timescaler,
spec_times[-1]*timescaler,
spec_freqs[fmask][0],
spec_freqs[fmask][-1],
],
aspect="auto",
origin="lower",
interpolation="gaussian",
alpha=1,
)
# ps.hide_xax(ax3)
ax3.set_xlabel("time [ms]")
ax2.set_ylabel("frequency [Hz]")
ax1.set_yticks(np.arange(400, 1201, 400))
ax1.spines.left.set_bounds((400, 1200))
ax2.set_yticks(np.arange(400, 1201, 400))
ax2.spines.left.set_bounds((400, 1200))
ax3.set_yticks(np.arange(400, 1201, 400))
ax3.spines.left.set_bounds((400, 1200))
plt.subplots_adjust(left=0.17, right=0.98, top=0.9,
bottom=0.14, hspace=0.35)
plt.savefig('../poster/figs/introplot.pdf')
plt.show()
if __name__ == '__main__':
main()

BIN
poster/figs/Untitled.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
poster/figs/algorithm.pdf Normal file

Binary file not shown.

BIN
poster/figs/introplot.pdf Normal file

Binary file not shown.

BIN
poster/figs/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

1184
poster/figs/logo.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

View File

@ -7,65 +7,101 @@ blockverticalspace=2mm, colspace=20mm, subcolspace=0mm]{tikzposter} %Default val
\begin{document} \begin{document}
\renewcommand{\baselinestretch}{1} \renewcommand{\baselinestretch}{1}
\title{\parbox{1900pt}{A dark template to make colorful figures pop}} \title{\parbox{1900pt}{Pushing the limits of time-frequency uncertainty in the
detection of transient communication signals in weakly electric fish}}
\author{Sina Prause, Alexander Wendt, Patrick Weygoldt} \author{Sina Prause, Alexander Wendt, Patrick Weygoldt}
\institute{Supervised by Till Raab \& Jan Benda} \institute{Supervised by Till Raab \& Jan Benda, Neurothology Group,
University of Tübingen}
\usetitlestyle[]{sampletitle} \usetitlestyle[]{sampletitle}
\maketitle \maketitle
\renewcommand{\baselinestretch}{1.4} \renewcommand{\baselinestretch}{1.4}
\begin{columns} \begin{columns}
\column{0.3} \column{0.5}
\myblock[TranspBlock]{Introduction}{ \myblock[TranspBlock]{Introduction}{
\lipsum[1][1-5] \begin{minipage}[t]{0.55\linewidth}
The time-frequency tradeoff makes reliable signal detecion and simultaneous
sender identification of freely interacting individuals impossible.
This profoundly limits our current understanding of chirps to experiments
with single - or physically separated - individuals.
\end{minipage} \hfill
\begin{minipage}[t]{0.40\linewidth}
\vspace{-1.5cm}
\begin{tikzfigure}[] \begin{tikzfigure}[]
\label{griddrawing} \label{tradeoff}
\includegraphics[width=\linewidth]{example-image-a} \includegraphics[width=\linewidth]{figs/introplot}
\end{tikzfigure} \end{tikzfigure}
\end{minipage}
} }
\myblock[TranspBlock]{Methods}{ \myblock[TranspBlock]{A chirp detection algorithm}{
\begin{tikzfigure}[] \begin{tikzfigure}[]
\label{detector} \label{modulations}
\includegraphics[width=\linewidth]{example-image-b} \includegraphics[width=\linewidth]{figs/algorithm}
\end{tikzfigure} \end{tikzfigure}
} }
\column{0.4} \column{0.5}
\myblock[TranspBlock]{Results}{ \myblock[TranspBlock]{Chirps and diadic competitions}{
\lipsum[3][1-5] \begin{minipage}[t]{0.7\linewidth}
\begin{tikzfigure}[] \begin{tikzfigure}[]
\label{modulations} \label{modulations}
\includegraphics[width=\linewidth]{example-image-c} \includegraphics[width=\linewidth]{figs/placeholder1}
\end{tikzfigure} \end{tikzfigure}
} \end{minipage} \hfill
\begin{minipage}[t]{0.25\linewidth}
\lipsum[3][1-3]
\end{minipage}
\myblock[TranspBlock]{More Stuff}{ \begin{minipage}[t]{0.7\linewidth}
\lipsum[3][1-9] \begin{tikzfigure}[]
} \label{modulations}
\includegraphics[width=\linewidth]{figs/placeholder1}
\end{tikzfigure}
\end{minipage} \hfill
\begin{minipage}[t]{0.25\linewidth}
\lipsum[3][1-3]
\end{minipage}
\column{0.3} \begin{minipage}[t]{0.7\linewidth}
\myblock[TranspBlock]{More Results}{
\begin{tikzfigure}[] \begin{tikzfigure}[]
\label{results} \label{modulations}
\includegraphics[width=\linewidth]{example-image-a} \includegraphics[width=\linewidth]{figs/placeholder1}
\end{tikzfigure} \end{tikzfigure}
\end{minipage} \hfill
\begin{minipage}[t]{0.25\linewidth}
\lipsum[3][1-3]
\end{minipage}
\begin{multicols}{2}
\lipsum[5][1-8]
\end{multicols}
\vspace{-1cm}
} }
\myblock[TranspBlock]{Conclusion}{ \myblock[TranspBlock]{Conclusion}{
\begin{itemize} \lipsum[3][1-9]
\setlength\itemsep{0.5em} }
\item \lipsum[1][1]
\item \lipsum[1][1] % \column{0.3}
\item \lipsum[1][1] % \myblock[TranspBlock]{More Results}{
\end{itemize} % \begin{tikzfigure}[]
\vspace{0.2cm} % \label{results}
} % \includegraphics[width=\linewidth]{example-image-a}
% \end{tikzfigure}
% \begin{multicols}{2}
% \lipsum[5][1-8]
% \end{multicols}
% \vspace{-1cm}
% }
% \myblock[TranspBlock]{Conclusion}{
% \begin{itemize}
% \setlength\itemsep{0.5em}
% \item \lipsum[1][1]
% \item \lipsum[1][1]
% \item \lipsum[1][1]
% \end{itemize}
% \vspace{0.2cm}
% }
\end{columns} \end{columns}
\node[ \node[
@ -78,6 +114,6 @@ blockverticalspace=2mm, colspace=20mm, subcolspace=0mm]{tikzposter} %Default val
fill=boxes, fill=boxes,
color=boxes, color=boxes,
] at (-0.51\paperwidth,-43.5) { ] at (-0.51\paperwidth,-43.5) {
\textcolor{text}{\normalsize Contact: name.surname@student.uni-tuebingen.de}}; \textcolor{text}{\normalsize Contact: \{name\}.\{surname\}@student.uni-tuebingen.de}};
\end{document} \end{document}