finished figure 3
This commit is contained in:
parent
2328e025c7
commit
5e254c2aaf
58
data/2021-08-03-ac-invivo-1/info.dat
Normal file
58
data/2021-08-03-ac-invivo-1/info.dat
Normal file
@ -0,0 +1,58 @@
|
||||
# Recording:
|
||||
# Recording quality: good
|
||||
# Comment : at end maldetection
|
||||
# Experimenter : Alexandra Rudnaya
|
||||
# WaterTemperature : 26.5°C
|
||||
# WaterConductivity: 300uS/cm
|
||||
# Cell:
|
||||
# CellType : unkown
|
||||
# Structure : Nerve
|
||||
# BrainRegion : P-units
|
||||
# BrainSubRegion : ~
|
||||
# Depth : 1330um
|
||||
# Lateral position : 0mm
|
||||
# Transverse section: 8
|
||||
# Cell properties:
|
||||
# Firing Rate1: 142Hz
|
||||
# P-Value1 : 0.21
|
||||
# X Position : 0mm
|
||||
# Y Position : 0mm
|
||||
# Subject:
|
||||
# Species : Apteronotus leptorhynchus
|
||||
# Gender : Female
|
||||
# Size : 15cm
|
||||
# Weight : 0.8g
|
||||
# Identifier : "2020lepto09"
|
||||
# EOD Frequency : 667Hz
|
||||
# Snout Position: 0mm
|
||||
# Tail Position : 0mm
|
||||
# Preparation:
|
||||
# Type : in vivo
|
||||
# Anaesthesia : true
|
||||
# Anaesthetic : MS 222
|
||||
# AnaestheticDose : 125mg/l
|
||||
# LocalAnaesthesia : true
|
||||
# LocalAnaesthetic : Lidocaine
|
||||
# Immobilization : true
|
||||
# ImmobilizationDrug: Tubocurarin 5mg/L
|
||||
# ImmobilizationDose: 75ul
|
||||
# Name : "2021-08-03-ac-invivo-1"
|
||||
# Folder : /home/efish/data/ephys/labrotation/2021-08-03-ac-invivo-1
|
||||
# File : [ trace-1.raw, trace-2.raw, trace-3.raw, trace-4.raw, trace-5.raw, stimulus-events.dat, restart-events.dat, recording-events.dat, spikes-1-events.dat, chirps-events.dat, localbeat-1-1-events.dat, localbeat-1-2-events.dat, stimuli.dat, stimulus-descriptions.dat ]
|
||||
# Date : "2021-08-03"
|
||||
# Time : "14:22:15.000"
|
||||
# Recording duratio: 25.27min
|
||||
# Mode : Acquisition
|
||||
# Software : RELACS
|
||||
# Software version : "0.9.8"
|
||||
# Setup:
|
||||
# Identifier: invivo1
|
||||
# Maintainer: Jan Grewe
|
||||
# Creator : Jan Grewe and Jan Benda
|
||||
# Location : "5A17"
|
||||
# Lab : Neuroethology Lab
|
||||
# Institute : Institute for Neurobiology
|
||||
# University: University Tuebingen
|
||||
# Address : Auf der Morgenstelle 28
|
||||
# Electrode:
|
||||
# Resistance: 0MOhm
|
||||
1000
data/2021-08-03-ac-invivo-1/stimuli.dat
Normal file
1000
data/2021-08-03-ac-invivo-1/stimuli.dat
Normal file
File diff suppressed because it is too large
Load Diff
690185
data/2021-08-03-ac-invivo-1/threefish-ams.dat
Normal file
690185
data/2021-08-03-ac-invivo-1/threefish-ams.dat
Normal file
File diff suppressed because it is too large
Load Diff
396453
data/2021-08-03-ac-invivo-1/threefish-spikes.dat
Normal file
396453
data/2021-08-03-ac-invivo-1/threefish-spikes.dat
Normal file
File diff suppressed because it is too large
Load Diff
@ -333,7 +333,7 @@ The P-unit model parameters and spectral analysis algorithms are available at \u
|
||||
The baseline firing rate $r$ was calculated as the number of spikes divided by the duration of the baseline recording (median 32\,s). The coefficient of variation (CV) of the interspike intervals (ISI) is their standard deviation relative to their mean: $\rm{CV}_{\rm base} = \sqrt{\langle (ISI- \langle ISI \rangle) ^2 \rangle} / \langle ISI \rangle$. If the baseline was recorded several times in a recording, the measures from the longest recording were taken.
|
||||
|
||||
\paragraph{White noise analysis} \label{response_modulation}
|
||||
When stimulated with band-limited white noise stimuli, neuronal activity is modulated around the average firing rate that is similar to the baseline firing rate and in that way encodes the time-course of the stimulus. For an estimate of the time-dependent firing rate $r(t)$ we convolved each spike train with normalized Gaussian kernels with standard deviation of 2\,ms, if not mentioned otherwise, and averaged the resulting single-trail firing rates over trials. The response modulation quantifies the variation of $r(t)$ computed as the standard deviation in time $\sigma_{s} = \sqrt{\langle (r(t)-\langle r(t) \rangle_t )^2\rangle_t}$, where $\langle \cdot \rangle_t$ denotes averaging over time.
|
||||
When stimulated with band-limited white noise stimuli, neuronal activity is modulated around the average firing rate that is similar to the baseline firing rate and in that way encodes the time-course of the stimulus. For an estimate of the time-dependent firing rate $r(t)$ we convolved each spike train with normalized Gaussian kernels with standard deviation of 2\,ms and averaged the resulting single-trail firing rates over trials. The response modulation quantifies the variation of $r(t)$ computed as the standard deviation in time $\sigma_{s} = \sqrt{\langle (r(t)-\langle r(t) \rangle_t )^2\rangle_t}$, where $\langle \cdot \rangle_t$ denotes averaging over time.
|
||||
|
||||
\paragraph{Spectral analysis}\label{susceptibility_methods}
|
||||
To characterize the relation between the spiking response evoked by white-noise stimuli, we estimated the first- and second-order susceptibilities in the frequency domain. For this we converted spike times into binary vectors $x_k$ with $\Delta t = 0.5$\,ms wide bins that are set to 2\,kHz where a spike occurred and zero otherwise. Fast Fourier transforms (FFT) $S(\omega)$ and $X(\omega)$ of the stimulus $s_k$ (also down-sampled to a sampling rate of 2\,kHz) and $x_k$, respectively, were computed numerically according to
|
||||
@ -401,7 +401,7 @@ Values larger than one indicate a sharp ridge in the susceptibility matrix close
|
||||
|
||||
|
||||
\begin{figure*}[t]
|
||||
\includegraphics[width=\columnwidth]{flowchart.pdf}
|
||||
\includegraphics[width=\columnwidth]{flowchart}
|
||||
\caption{\label{flowchart}
|
||||
Architecture of the P-unit model. Each row illustrates subsequent processing steps for three different stimulation regimes: (i) baseline activity without external stimulus, only the fish's self-generated EOD (the carrier, \eqnref{eq:eod}) is present. (ii) RAM stimulation, \eqnref{eq:ram_equation}. The amplitude of the EOD carrier is modulated with a weak (2\,\% contrast) band-limited white-noise stimulus. (iii) Noise split, \eqnsref{eq:ram_split}--\eqref{eq:Noise_split_intrinsic}, where 90\,\% of the intrinsic noise is replaced by a RAM stimulus, whose amplitude is scaled to maintain the mean firing rate and the CV of the ISIs of the model's baseline activity. As an example, simulations of the model for cell ``2012-07-03-ak'' are shown. \figitem{A} The stimuli are thresholded, \eqnref{eq:threshold2}, by setting all negative values to zero. \figitem{B} Subsequent low-pass filtering, \eqnref{eq:dendrite}, attenuates the carrier and carves out the AM signal. \figitem{C} Intrinsic Gaussian white-noise is added to the signals shown in \panel{B}. Note the reduced internal noise amplitude in the noise split (iii) condition. \figitem{D} Spiking output of the LIF model, \eqnsref{eq:LIF}--\eqref{spikethresh}, in response to the sum of \panel{B} and \panel{C}. \figitem{E} Power spectra of the LIF neuron's spiking activity. Both, baseline activity (\panel[i]{E}) and noise split (\panel[iii]{E}), have the same peaks in the response spectrum at $r$, $f_{EOD} - r$, $f_{EOD}$, and $f_{EOD} + r$. With RAM stimulation (\panel[ii]{E}), the peak at the baseline firing rate, $r$, is washed out.}
|
||||
\end{figure*}
|
||||
@ -485,9 +485,8 @@ Both, the reduced intrinsic noise and the RAM stimulus, need to replace the orig
|
||||
\section{Results}
|
||||
|
||||
\begin{figure*}[t]
|
||||
\includegraphics[width=\columnwidth]{motivation.pdf}
|
||||
\caption{\label{fig:motivation} Nonlinearity in an electrophysiologically recorded P-unit of \lepto{} in a three-fish setting (cell identifier ``2021-08-03-ac"). Receiver with EOD frequency $f_{\rm EOD} =664$\,Hz encounters fish with EOD frequencies $f_{1}=631$\,Hz and $f_{2}=797$\,Hz. Both foreign signals have the same strength relative to the own field amplitude (10\,\% contrast). Top row: Sketch of signal processing in the nonlinear system (black box). Second row: Interference of the receiver EOD with the EODs of other fish, bold line highlights the amplitude modulation. Third row: Respective spike trains of the recorded P-unit. Fourth row: Firing rate, estimated by convolution of the spike trains with a Gaussian kernel ($\sigma = 1$\,ms). Bottom row: Power spectrum of the firing rate. \figitem{A} Baseline condition: The cell is driven by the self-generated field alone. The baseline firing rate $r$ dominates the power spectrum of the firing rate ($f_{base} = 139$\,Hz). \figitem{B} The receiver's EOD and a foreign fish with an EOD frequency $f_{1}=631$\,Hz are present. EOD interference induces an amplitude modulation, referred to as beat. \figitem{C} The receiver and a fish with an EOD frequency $f_{2}=797$\,Hz are present. The resulting beat is faster as the difference between the individual frequencies is larger. \figitem{D} All three fish with the EOD frequencies $f_{\rm EOD}$, $f_1$ and $f_2$ are present. A second-order amplitude modulation occurs, commonly referred to as envelope. Nonlinear peaks occur at the sum and difference of the two beat frequencies in the power spectrum of the firing rate.
|
||||
}
|
||||
\includegraphics[width=\columnwidth]{twobeats}
|
||||
\caption{\label{fig:motivation} Nonlinearity in an electrophysiologically recorded P-unit of \lepto{} in a three-fish setting (cell identifier ``2021-08-03-ac"). Receiver with EOD frequency $f_{\rm EOD} =664$\,Hz encounters fish with EOD frequencies $f_{1}=631$\,Hz and $f_{2}=797$\,Hz. Both foreign signals have the same strength relative to the own field amplitude (10\,\% contrast). Top row: Sketch of signal processing in the nonlinear system (black box). Second row: Superposition of the receiver EOD with the EODs of other fish, colored line highlights the amplitude modulation. Third row: Three trials of spike trains of the recorded P-unit. Fourth row: Firing rate, estimated by convolution of the spike trains with a Gaussian kernel. Bottom row: Power spectrum of the spike trains. \figitem{A} Baseline condition: The cell is driven by the self-generated field alone. The baseline firing rate $r = 139$\,Hz dominates the power spectrum. \figitem{B} The receiver's EOD and a single conspecific with an EOD frequency $f_{1}=631$\,Hz are present. Superposition of the two EODs induces an amplitude modulation, referred to as beat, with beat frequeny $\Delta f_1=33$\,Hz. \figitem{C} The receiver and a fish with an EOD frequency $f_{2}=797$\,Hz are present. The resulting beat $\Delta f_2=133$\,Hz is faster as the difference between the EOD frequencies is larger. \figitem{D} All three fish with EOD frequencies $f_{\rm EOD}$, $f_1$, and $f_2$ are present. A second-order amplitude modulation occurs, commonly referred to as envelope. Additional peaks occur in the power spectrum of the spike response at the sum and difference of the two beat frequencies, indicating non-linear interactions between the tow frequencies in the P-unit.}
|
||||
\end{figure*}
|
||||
|
||||
We explored a large set of electrophysiological data from primary afferents of the active and passive electrosensory system, P-units and ampullary cells \citep{Grewe2017, Hladnik2023}, that were recorded in the brown ghost knifefish \textit{Apteronotus leptorhynchus}. We re-analyzed this dataset to search for weakly nonlinear responses that have been predicted in previous theoretical work \citep{Voronenko2017}. Additional simulations of LIF-based models of P-unit spiking help to interpret the experimental findings in this theoretical framework. We start with demonstrating the basic concepts using example P-units and respective models and then compare the population of recordings in both cell types.
|
||||
@ -502,7 +501,7 @@ When stimulating with both foreign signals simultaneously, additional peaks appe
|
||||
|
||||
\begin{figure*}[p]
|
||||
\includegraphics[width=\columnwidth]{regimes}
|
||||
\caption{\label{fig:regimes} Linear and nonlinear responses of a model P-unit in a three-fish setting in dependence on stimulus amplitudes. The model P-unit (identifier ``2018-05-08-ad'') was stimulated with two sine waves of equal amplitude (contrast) at difference frequencies $\Delta f_1=40$\,Hz and $\Delta f_2=228$\,Hz relative the receiver's EOD frequency. $\Delta f_2$ was set to match the baseline firing rate $r$ of the P-unit. \figitem{A--D} Top: the stimulus, an amplitude modulation of the receiver's EOD resulting from the stimulation with the two sine waves. The contrasts of both beats increase from \panel{A} to \panel{D} as indicated. Middle: Spike raster of the model P-unit response. Bottom: power spectrum of the firing rate estimated from the spike raster. \figitem{A} At low stimulus contrasts the response is linear. The only peaks in the response spectrum are at the two stimulating beat frequencies (green and purple marker). \figitem{B} At moderately higher stimulus contrast, the peaks in the response spectrum at the two beat frequencies are larger. \figitem{C} At intermediate stimulus contrasts, nonlinear responses start to appear at the sum and the difference of the stimulus frequencies (orange and red marker). \figitem{D} At higher stimulus contrasts additional peaks appear in the power spectrum. \figitem{E} Amplitude of the linear (at $\Delta f_1$ and $\Delta f_2$) and nonlinear (at $\Delta f_2 - \Delta f_1$ and $\Delta f_1 + \Delta f_2$) responses of the model P-unit as a function of beat contrast (thick lines). Thin lines indicate the initial linear and quadratic dependence on stimulus amplitude for the linear and nonlinear responses, respectively. In the linear regime, below a stimulus contrast of about 1.2\,\% (left vertical line), the only peaks in the response spectrum are at the stimulus frequencies. In the weakly nonlinear regime up to a contrast of about 3.5\,\% peaks arise at the sum and the difference of the two stimulus frequencies. At stronger stimulation the amplitudes of these nonlinear responses deviate from the quadratic dependency on stimulus contrast.}
|
||||
\caption{\label{fig:regimes} Linear and nonlinear responses of a model P-unit in a three-fish setting in dependence on stimulus amplitudes. The model P-unit (identifier ``2018-05-08-ad'') was stimulated with two sine waves of equal amplitude (contrast) at difference frequencies $\Delta f_1=40$\,Hz and $\Delta f_2=228$\,Hz relative the receiver's EOD frequency. $\Delta f_2$ was set to match the baseline firing rate $r$ of the P-unit. \figitem{A--D} Top: the stimulus, an amplitude modulation of the receiver's EOD resulting from the stimulation with the two sine waves. The contrasts of both beats increase from \panel{A} to \panel{D} as indicated. Middle: Spike raster of the model P-unit response. Bottom: power spectrum of the firing rate estimated from the spike raster. \figitem{A} At low stimulus contrasts the response is linear. The only peaks in the response spectrum are at the two stimulating beat frequencies (green and purple marker), the latter enhancing the peak at baseline firig rate (blue). The largest peak, however, is always the one atthe EOD frequency of the receiver (black). Here also flanked by harmonics of $\Delta f_1$ (small black markers). \figitem{B} At moderately higher stimulus contrast, the peaks in the response spectrum at the two beat frequencies become larger. In addition, a peak at $f_{EOD} - \Delta f_2 $ appears. \figitem{C} At intermediate stimulus contrasts, nonlinear responses start to appear at the sum and the difference of the stimulus frequencies (orange and red). Additional peaks appear at harmonics of $\Delta f_1$ (small green markers) and at $f_{EOD} \Delta f_2 \pm \Delta f_1$ (small purple marker). \figitem{D} At higher stimulus contrasts further peaks appear in the power spectrum. \figitem{E} Amplitude of the linear (at $\Delta f_1$ and $\Delta f_2$) and nonlinear (at $\Delta f_2 - \Delta f_1$ and $\Delta f_1 + \Delta f_2$) responses of the model P-unit as a function of beat contrast (thick lines). Thin lines indicate the initial linear and quadratic dependence on stimulus amplitude for the linear and nonlinear responses, respectively. In the linear regime, below a stimulus contrast of about 1.2\,\% (left vertical line), the only peaks in the response spectrum are at the stimulus frequencies. In the weakly nonlinear regime up to a contrast of about 3.5\,\% peaks arise at the sum and the difference of the two stimulus frequencies. At stronger stimulation the amplitudes of these nonlinear responses deviate from the quadratic dependency on stimulus contrast.}
|
||||
\end{figure*}
|
||||
|
||||
The stimuli used in \figref{fig:motivation} had the same not-small amplitude. Whether this stimulus condition falls into the weakly nonlinear regime as in \citet{Voronenko2017} is not clear. In order to illustrate how the responses to two beat frequencies develop over a range of amplitudes we use a stochastic leaky-integrate-and-fire (LIF) based P-unit model fitted to a specific electrophysiologically measured cell \citep{Barayeu2023}.
|
||||
|
||||
38
plotstyle.py
38
plotstyle.py
@ -137,23 +137,29 @@ def plot_style():
|
||||
ns.lsRaster = dict(color=palette['black'], lw=ns.lwthin)
|
||||
ns.lsRate = dict(color=palette['blue'], lw=ns.lwmid)
|
||||
ns.lsPower = dict(color=palette['gray'], lw=ns.lwmid)
|
||||
ns.lsF0 = dict(color='blue', lw=ns.lwthick)
|
||||
ns.lsF01 = dict(color='green', lw=ns.lwthick)
|
||||
ns.lsF02 = dict(color='purple', lw=ns.lwthick)
|
||||
ns.lsF012 = dict(color='orange', lw=ns.lwthick)
|
||||
ns.lsF01_2 = dict(color='red', lw=ns.lwthick)
|
||||
ns.lsF0m = dict(color=lighter('blue', 0.5), lw=ns.lwthin)
|
||||
ns.lsF01m = dict(color=lighter('green', 0.6), lw=ns.lwthin)
|
||||
ns.lsF02m = dict(color=lighter('purple', 0.5), lw=ns.lwthin)
|
||||
ns.lsF012m = dict(color=darker('orange', 0.9), lw=ns.lwthin)
|
||||
ns.lsF01_2m = dict(color=darker('red', 0.9), lw=ns.lwthin)
|
||||
ns.lsF0 = dict(color=palette['blue'], lw=ns.lwthick)
|
||||
ns.lsF01 = dict(color=palette['green'], lw=ns.lwthick)
|
||||
ns.lsF02 = dict(color=palette['purple'], lw=ns.lwthick)
|
||||
ns.lsF012 = dict(color=palette['orange'], lw=ns.lwthick)
|
||||
ns.lsF01_2 = dict(color=palette['red'], lw=ns.lwthick)
|
||||
ns.lsF0m = dict(color=lighter(palette['blue'], 0.5), lw=ns.lwthin)
|
||||
ns.lsF01m = dict(color=lighter(palette['green'], 0.6), lw=ns.lwthin)
|
||||
ns.lsF02m = dict(color=lighter(palette['purple'], 0.5), lw=ns.lwthin)
|
||||
ns.lsF012m = dict(color=darker(palette['orange'], 0.9), lw=ns.lwthin)
|
||||
ns.lsF01_2m = dict(color=darker(palette['red'], 0.9), lw=ns.lwthin)
|
||||
|
||||
ns.psFEOD = dict(color='black', marker='o', linestyle='none', markersize=5, mec='none', mew=0)
|
||||
ns.psF0 = dict(color='blue', marker='o', linestyle='none', markersize=5, mec='none', mew=0)
|
||||
ns.psF01 = dict(color='green', marker='o', linestyle='none', markersize=5, mec='none', mew=0)
|
||||
ns.psF02 = dict(color='purple', marker='o', linestyle='none', markersize=5, mec='none', mew=0)
|
||||
ns.psF012 = dict(color='orange', marker='o', linestyle='none', markersize=5, mec='none', mew=0)
|
||||
ns.psF01_2 = dict(color='red', marker='o', linestyle='none', markersize=5, mec='none', mew=0)
|
||||
ns.psFEOD = dict(color=palette['black'], marker='o', linestyle='none', markersize=4, mec='none', mew=0)
|
||||
ns.psF0 = dict(color=palette['blue'], marker='o', linestyle='none', markersize=4, mec='none', mew=0)
|
||||
ns.psF01 = dict(color=palette['green'], marker='o', linestyle='none', markersize=4, mec='none', mew=0)
|
||||
ns.psF02 = dict(color=palette['purple'], marker='o', linestyle='none', markersize=4, mec='none', mew=0)
|
||||
ns.psF012 = dict(color=palette['orange'], marker='o', linestyle='none', markersize=4, mec='none', mew=0)
|
||||
ns.psF01_2 = dict(color=palette['red'], marker='o', linestyle='none', markersize=4, mec='none', mew=0)
|
||||
ns.psFEODm = dict(color=palette['black'], marker='o', linestyle='none', markersize=3, mec='none', mew=0)
|
||||
ns.psF0m = dict(color=palette['blue'], marker='o', linestyle='none', markersize=3, mec='none', mew=0)
|
||||
ns.psF01m = dict(color=palette['green'], marker='o', linestyle='none', markersize=3, mec='none', mew=0)
|
||||
ns.psF02m = dict(color=palette['purple'], marker='o', linestyle='none', markersize=3, mec='none', mew=0)
|
||||
ns.psF012m = dict(color=palette['orange'], marker='o', linestyle='none', markersize=3, mec='none', mew=0)
|
||||
ns.psF01_2m = dict(color=palette['red'], marker='o', linestyle='none', markersize=3, mec='none', mew=0)
|
||||
|
||||
ns.model_color1 = palette['purple']
|
||||
ns.model_color2 = lighter(ns.model_color1, 0.6)
|
||||
|
||||
@ -250,7 +250,16 @@
|
||||
frequencies to illustrate these and it is not clear why these are
|
||||
clipped in these two figures.}
|
||||
|
||||
\response{HM. LETS CHECK HOW IT LOOKS LIKE. BUT THIS LOW FREQUENCY RANGE IS THE RELEVANT ONE FOR CODING.}
|
||||
\response{You are right. In figure 4 we show now the spectrum up to
|
||||
750Hz, such that fEOD and its interactions with df2 and harmonics
|
||||
are included. We labeled the additonal peaks accordingly. In figure
|
||||
3 we stay with the small range, because we have so little data (only
|
||||
three trials of 500ms duration) for this special setting where one
|
||||
of the beat frequencies approximately matches the P-units baseline
|
||||
firing rate. This is why the power spectra are very noisy. Also, for
|
||||
an introductory figure we prefer to only show the few peaks that are
|
||||
relevant for the rest of the manuscript, such that the reader does
|
||||
not get overwhelmed. }
|
||||
|
||||
\issue{(6) Figure 3. Why are these example firing rates based on
|
||||
convolution with a 1 ms Gaussian kernel if the analyses were based
|
||||
@ -259,7 +268,9 @@
|
||||
actually analyzed. More fundamentally, why would a 2-fold difference
|
||||
in kernel width be appropriate for presentation vs. analysis?}
|
||||
|
||||
\response{DAMN. LETS REDO THE FIGURE.}
|
||||
\response{This was for historical reasons. We updated figure 3 to also
|
||||
use the 2ms kernel. Now all firing rates in the manuscript are based
|
||||
on the 2ms kernel.}
|
||||
|
||||
\issue{(7) Figure 3D legend. The relationship between 2nd order AM
|
||||
(envelope) and the two nonlinear peaks should be made clear. I
|
||||
|
||||
52
regimes.py
52
regimes.py
@ -178,8 +178,14 @@ def decibel(x):
|
||||
return 10*np.log10(x/1e8)
|
||||
|
||||
|
||||
def plot_psd(ax, s, path, contrast, spikes, nfft, dt, beatf1, beatf2):
|
||||
offs = 4
|
||||
def peak_ampl(freqs, psd, f, df=2):
|
||||
psd_snippet = psd[(freqs > f - df) & (freqs < f + df)]
|
||||
return np.max(psd_snippet)
|
||||
|
||||
|
||||
def plot_psd(ax, s, path, contrast, spikes, nfft, dt, beatf1, beatf2, eodf):
|
||||
offs = 5
|
||||
offsm = 3
|
||||
freqs, psd = compute_power(path, contrast, spikes, nfft, dt)
|
||||
psd /= freqs[1]
|
||||
ax.plot(freqs, decibel(psd), **s.lsPower)
|
||||
@ -187,19 +193,36 @@ def plot_psd(ax, s, path, contrast, spikes, nfft, dt, beatf1, beatf2):
|
||||
label=r'$r$', clip_on=False, **s.psF0)
|
||||
ax.plot(beatf1, decibel(peak_ampl(freqs, psd, beatf1)) + offs,
|
||||
label=r'$\Delta f_1$', clip_on=False, **s.psF01)
|
||||
ax.plot(beatf2, decibel(peak_ampl(freqs, psd, beatf2)) + 2*offs + 3,
|
||||
ax.plot(beatf2, decibel(peak_ampl(freqs, psd, beatf2)) + 2*offs + 2,
|
||||
label=r'$\Delta f_2$', clip_on=False, **s.psF02)
|
||||
ax.plot(beatf2 - beatf1, decibel(peak_ampl(freqs, psd, beatf2 - beatf1)) + offs,
|
||||
label=r'$\Delta f_2 - \Delta f_1$', clip_on=False, **s.psF01_2)
|
||||
ax.plot(beatf1 + beatf2, decibel(peak_ampl(freqs, psd, beatf1 + beatf2)) + offs,
|
||||
label=r'$\Delta f_1 + \Delta f_2$', clip_on=False, **s.psF012)
|
||||
ax.set_xlim(0, 300)
|
||||
ax.plot(eodf, decibel(peak_ampl(freqs, psd, eodf)) + offs,
|
||||
label=r'$f_{EOD}$', clip_on=False, **s.psFEOD)
|
||||
ax.plot(eodf + beatf1, decibel(peak_ampl(freqs, psd, eodf + beatf1)) + offsm, label=r'$f_{EOD} \pm k \Delta f_1$', **s.psFEODm)
|
||||
ax.plot(eodf - beatf1, decibel(peak_ampl(freqs, psd, eodf - beatf1)) + offsm, **s.psFEODm)
|
||||
if contrast > 0.02:
|
||||
ax.plot(2*beatf1, decibel(peak_ampl(freqs, psd, 2*beatf1)) + offsm, label=r'$k\Delta f_1$', **s.psF01m)
|
||||
ax.plot(eodf + 2*beatf1, decibel(peak_ampl(freqs, psd, eodf + 2*beatf1)) + offsm, **s.psFEODm)
|
||||
if contrast > 0.008:
|
||||
ax.plot(eodf - beatf2, decibel(peak_ampl(freqs, psd, eodf - beatf2)) + offsm, label=r'$f_{EOD} - \Delta f_2$', **s.psF0m)
|
||||
if contrast > 0.02:
|
||||
ax.plot(eodf - beatf2 + beatf1, decibel(peak_ampl(freqs, psd, eodf - beatf2 + beatf1)) + offsm, label=r'$f_{EOD} - \Delta f_2 \pm \Delta f_1$', **s.psF02m)
|
||||
ax.plot(eodf - beatf2 - beatf1, decibel(peak_ampl(freqs, psd, eodf - beatf2 - beatf1)) + offsm, **s.psF02m)
|
||||
if contrast > 0.05:
|
||||
ax.plot(3*beatf1, decibel(peak_ampl(freqs, psd, 3*beatf1)) + offsm, **s.psF01m)
|
||||
ax.plot(4*beatf1, decibel(peak_ampl(freqs, psd, 4*beatf1)) + offsm, **s.psF01m)
|
||||
ax.plot(eodf - 2*beatf1, decibel(peak_ampl(freqs, psd, eodf - 2*beatf1)) + offsm, **s.psFEODm)
|
||||
ax.set_xlim(0, 750)
|
||||
ax.set_ylim(-60, 0)
|
||||
ax.set_xticks_delta(200)
|
||||
ax.set_xlabel('Frequency', 'Hz')
|
||||
ax.set_ylabel('Power [dB]')
|
||||
|
||||
|
||||
def plot_example(axs, axr, axp, s, path, cell, alpha, beatf1, beatf2,
|
||||
def plot_example(axs, axr, axp, s, path, cell, alpha, beatf1, beatf2, eodf,
|
||||
nfft, trials):
|
||||
dt = 0.0001
|
||||
tmax = nfft*dt
|
||||
@ -207,13 +230,7 @@ def plot_example(axs, axr, axp, s, path, cell, alpha, beatf1, beatf2,
|
||||
spikes = punit_spikes(cell, alpha, beatf1, beatf2, tmax, trials)
|
||||
plot_am(axs, s, alpha, beatf1, beatf2, t1)
|
||||
plot_raster(axr, s, spikes, t1)
|
||||
plot_psd(axp, s, path, alpha, spikes, nfft, dt, beatf1, beatf2)
|
||||
|
||||
|
||||
def peak_ampl(freqs, psd, f):
|
||||
df = 2
|
||||
psd_snippet = psd[(freqs > f - df) & (freqs < f + df)]
|
||||
return np.max(psd_snippet)
|
||||
plot_psd(axp, s, path, alpha, spikes, nfft, dt, beatf1, beatf2, eodf)
|
||||
|
||||
|
||||
def amplitude(power):
|
||||
@ -296,6 +313,7 @@ if __name__ == '__main__':
|
||||
|
||||
parameters = load_models(data_path / 'punitmodels.csv')
|
||||
cell = cell_parameters(parameters, model_cell)
|
||||
eodf = cell['EODf']
|
||||
nfft = 2**18
|
||||
|
||||
print(f'Loaded data for cell {model_cell}: ')
|
||||
@ -305,20 +323,20 @@ if __name__ == '__main__':
|
||||
|
||||
s = plot_style()
|
||||
fig, (axes, axa) = plt.subplots(2, 1, height_ratios=[4, 3],
|
||||
cmsize=(s.plot_width, 0.6*s.plot_width))
|
||||
cmsize=(s.plot_width, 0.65*s.plot_width))
|
||||
fig.subplots_adjust(leftm=8, rightm=2, topm=2, bottomm=3.5, hspace=0.6)
|
||||
axe = axes.subplots(3, 4, wspace=0.4, hspace=0.2,
|
||||
height_ratios=[1, 2, 3])
|
||||
height_ratios=[1, 2, 0.6, 3])
|
||||
fig.show_spines('lb')
|
||||
|
||||
# example power spectra:
|
||||
for c, alpha in enumerate(alphas):
|
||||
path = sims_path / f'{model_cell}-contrastspectrum-{1000*alpha:03.0f}.npz'
|
||||
plot_example(axe[0, c], axe[1, c], axe[2, c], s, path,
|
||||
cell, alpha, beatf1, beatf2, nfft, 100)
|
||||
cell, alpha, beatf1, beatf2, eodf, nfft, 100)
|
||||
axe[1, 0].xscalebar(1, -0.1, 20, 'ms', ha='right')
|
||||
axe[2, 0].legend(loc='center left', bbox_to_anchor=(0, -0.8),
|
||||
ncol=5, columnspacing=2)
|
||||
axe[2, 3].legend(loc='center right', bbox_to_anchor=(1, -0.8),
|
||||
ncol=10, columnspacing=1, handletextpad=0.1)
|
||||
fig.common_yspines(axe[0, :])
|
||||
fig.common_yticks(axe[2, :])
|
||||
fig.tag(axe[0, :], xoffs=-3, yoffs=1.6)
|
||||
|
||||
313
twobeats.py
313
twobeats.py
@ -3,6 +3,7 @@ import matplotlib.pyplot as plt
|
||||
|
||||
from pathlib import Path
|
||||
from scipy.stats import norm
|
||||
from scipy.optimize import curve_fit
|
||||
from spectral import rate
|
||||
from plotstyle import plot_style
|
||||
|
||||
@ -12,21 +13,13 @@ cell = '2021-08-03-ac-invivo-1'
|
||||
data_path = Path('data')
|
||||
|
||||
|
||||
def load_data(cell_path, f1=797, f2=631):
|
||||
def load_spikes(cell_path, f1=797, f2=631):
|
||||
load = False
|
||||
spikes = []
|
||||
index = 0
|
||||
with open(cell_path / 'threefish-spikes.dat') as sf:
|
||||
for line in sf:
|
||||
if line.startswith('# EOD rate '):
|
||||
eodf = float(line.split(':')[1].strip().replace('Hz', ''))
|
||||
elif line.startswith('# Deltaf1 '):
|
||||
df1 = float(line.split(':')[1].strip().replace('Hz', ''))
|
||||
elif line.startswith('# Deltaf2 '):
|
||||
df2 = float(line.split(':')[1].strip().replace('Hz', ''))
|
||||
if abs(eodf + df1 - f1) < 1 and abs(eodf + df2 - f2) < 1:
|
||||
#print(f'EODf={eodf:6.1f}Hz, Df1={df1:6.1f}Hz, Df2={df2:6.1f}Hz, EODf1={eodf + df1:6.1f}Hz, EODf2={eodf + df2:6.1f}Hz')
|
||||
load = True
|
||||
elif load:
|
||||
if load:
|
||||
if ' before:' in line:
|
||||
t0 = 0.001*float(line.split(':')[1].strip().replace('ms', ''))
|
||||
elif ' duration1 ' in line:
|
||||
@ -38,7 +31,7 @@ def load_data(cell_path, f1=797, f2=631):
|
||||
elif line.startswith('# index '):
|
||||
if len(spikes) > 0:
|
||||
spikes[-1] = np.array(spikes[-1])
|
||||
return spikes, eodf, df1, df2, t0, t1, t2, t12
|
||||
return spikes, eodf, df1, df2, t0, t1, t2, t12, index
|
||||
elif line.startswith('# trial:'):
|
||||
if len(spikes) > 0:
|
||||
spikes[-1] = np.array(spikes[-1])
|
||||
@ -46,71 +39,197 @@ def load_data(cell_path, f1=797, f2=631):
|
||||
elif len(line.strip()) > 0 and line[0] != '#':
|
||||
t = 0.001*float(line.strip())
|
||||
spikes[-1].append(t)
|
||||
elif line.startswith('# index '):
|
||||
index += 1
|
||||
elif line.startswith('# EOD rate '):
|
||||
eodf = float(line.split(':')[1].strip().replace('Hz', ''))
|
||||
elif line.startswith('# Deltaf1 '):
|
||||
df1 = float(line.split(':')[1].strip().replace('Hz', ''))
|
||||
elif line.startswith('# Deltaf2 '):
|
||||
df2 = float(line.split(':')[1].strip().replace('Hz', ''))
|
||||
if abs(eodf + df1 - f1) < 1 and abs(eodf + df2 - f2) < 1:
|
||||
#print(f'EODf={eodf:6.1f}Hz, Df1={df1:6.1f}Hz, Df2={df2:6.1f}Hz, EODf1={eodf + df1:6.1f}Hz, EODf2={eodf + df2:6.1f}Hz')
|
||||
load = True
|
||||
print(f'no spikes found for EODf1={f1:.1f}Hz and EODf2={f2:.1f}Hz')
|
||||
|
||||
|
||||
def align_spikes(spikes, period):
|
||||
# compute rates for each trial:
|
||||
tmax = np.max([s[-1] for s in spikes])
|
||||
time = np.arange(0, tmax, 0.0002)
|
||||
sigma = 0.001
|
||||
kernel = norm.pdf(time[time < 8*sigma], loc=4*sigma, scale=sigma)
|
||||
rates = []
|
||||
xtime = np.append(time, time[-1] + time[1] - time[0])
|
||||
for i, spiket in enumerate(spikes):
|
||||
b, _ = np.histogram(spiket, xtime)
|
||||
r = np.convolve(b, kernel, 'same')
|
||||
rates.append(r)
|
||||
# align them on the first trial:
|
||||
nrates = len(rates[0])
|
||||
for i in range(1, len(rates)):
|
||||
rs = []
|
||||
n = len(time[time <= period])
|
||||
if n < 2:
|
||||
n = 2
|
||||
for k in range(1, 1 + n):
|
||||
r = np.corrcoef(rates[0][:-k], rates[i][k:])[0, 1]
|
||||
rs.append(r)
|
||||
k = 1 + np.argmax(rs)
|
||||
dt = time[k]
|
||||
spikes[i] -= dt
|
||||
print(f' shift trial {i} by {1000*dt:.0f}ms')
|
||||
def load_am(cell_path, inx):
|
||||
load = False
|
||||
ams = []
|
||||
index = 0
|
||||
with open(cell_path / 'threefish-ams.dat') as sf:
|
||||
for line in sf:
|
||||
if load:
|
||||
if line.startswith('# index '):
|
||||
if len(ams) > 0:
|
||||
ams[-1] = np.array(ams[-1])
|
||||
return ams
|
||||
elif line.startswith('# EOD rate '):
|
||||
print(f' EODf = {line.split(':')[1].strip()}')
|
||||
elif line.startswith('# Deltaf1 '):
|
||||
print(f' Df1 = {line.split(':')[1].strip()}')
|
||||
elif line.startswith('# Deltaf2 '):
|
||||
print(f' DF2 = {line.split(':')[1].strip()}')
|
||||
elif line.startswith('# trial:'):
|
||||
if len(ams) > 0:
|
||||
ams[-1] = np.array(ams[-1])
|
||||
ams.append([])
|
||||
elif len(line.strip()) > 0 and line[0] != '#':
|
||||
time, am = line.split()
|
||||
t = 0.001*float(time.strip())
|
||||
a = float(am.strip())
|
||||
ams[-1].append((t, a))
|
||||
elif line.startswith('# index '):
|
||||
index += 1
|
||||
if inx == index:
|
||||
load = True
|
||||
print(f'no AM found at index {inx}')
|
||||
|
||||
|
||||
def cosine(x, a, f, p, c):
|
||||
return a*np.cos(2*np.pi*f*x + p) + c
|
||||
|
||||
|
||||
def two_cosine(x, a1, f1, p1, a2, f2, p2, c):
|
||||
return a1*np.cos(2*np.pi*f1*x + p1) + a2*np.cos(2*np.pi*f2*x + p2) + c
|
||||
|
||||
|
||||
def am_phases(ams, eodf, df1, df2, t1, t2, t12):
|
||||
twins = (t1, t2, t12)
|
||||
dfs = ((df1,), (df2,), (df1, df2))
|
||||
phases = np.zeros((len(ams), len(dfs) + 1))
|
||||
for k in range(len(ams)):
|
||||
t0 = 0
|
||||
time = ams[k][:, 0]
|
||||
am = ams[k][:, 1]
|
||||
for i in range(len(twins)):
|
||||
tw = twins[0]
|
||||
t1 = t0 + tw
|
||||
mask = (time >= t0) & (time <= t1)
|
||||
tam = time[mask] - t0
|
||||
aam = am[mask]
|
||||
a = 0.5*(np.max(aam) - np.min(aam))
|
||||
c = np.mean(aam)
|
||||
tt = np.linspace(0, tw, 1000)
|
||||
if len(dfs[i]) == 2:
|
||||
popt = [a/2, dfs[i][0], 0, a/2, dfs[i][1], 0, c]
|
||||
popt, _ = curve_fit(two_cosine, tam, aam, popt)
|
||||
aa = two_cosine(tt, *popt)
|
||||
phases[k, i] = popt[2] if popt[0] > 0 else popt[2] + np.pi
|
||||
phases[k, i + 1] = popt[5] if popt[3] > 0 else popt[5] + np.pi
|
||||
else:
|
||||
popt = [a, dfs[i][0], 0, c]
|
||||
popt, _ = curve_fit(cosine, tam, aam, popt)
|
||||
aa = cosine(tt, *popt)
|
||||
phases[k, i] = popt[2] if popt[0] > 0 else popt[2] + np.pi
|
||||
t0 = t1
|
||||
return phases
|
||||
|
||||
|
||||
def align_spikes(spikes, freqs, phases):
|
||||
f1, f2 = freqs
|
||||
if f1 is None and f2 is None:
|
||||
return spikes
|
||||
p1 = phases[0]
|
||||
p2 = phases[1]
|
||||
if f2 is None:
|
||||
df = f1
|
||||
p = p1
|
||||
else:
|
||||
df = f2
|
||||
p = p2
|
||||
for i in range(len(spikes)):
|
||||
spikes[i] += p[i]/2/np.pi/df
|
||||
return spikes
|
||||
|
||||
|
||||
def plot_symbols(ax, s):
|
||||
def baseline_rate(spikes, t0, t1):
|
||||
rates = []
|
||||
for times in spikes:
|
||||
c = np.sum((times > t0) & (times < t1))
|
||||
rates.append(c/(t1 - t0))
|
||||
return np.mean(rates)
|
||||
|
||||
|
||||
def power_spectrum(spikes, tmax, dt=0.0005, nfft=512, p_ref=4000):
|
||||
time = np.arange(0, tmax, dt)
|
||||
if nfft > len(time):
|
||||
print('nfft too large:', nfft, len(time))
|
||||
freqs = np.fft.fftfreq(nfft, dt)
|
||||
freqs = np.fft.fftshift(freqs)
|
||||
segments = range(0, len(time) - nfft, nfft)
|
||||
p_rr = np.zeros(len(freqs))
|
||||
n = 0
|
||||
for i, spiket in enumerate(spikes):
|
||||
b, _ = np.histogram(spiket, time)
|
||||
b = b / dt
|
||||
for j, k in enumerate(segments):
|
||||
fourier_r = np.fft.fft(b[k:k + nfft] - np.mean(b), n=nfft)
|
||||
fourier_r = np.fft.fftshift(fourier_r)
|
||||
p_rr += np.abs(fourier_r*np.conj(fourier_r))
|
||||
n += 1
|
||||
mask = freqs >= 0.0
|
||||
freqs = freqs[mask]
|
||||
scale = dt/nfft/n
|
||||
p_rr = p_rr[mask]*scale
|
||||
power = 10*np.log10(p_rr/p_ref)
|
||||
return freqs, power
|
||||
|
||||
|
||||
def plot_symbols(ax, s, freqs):
|
||||
f1, f2 = freqs
|
||||
ax.show_spines('')
|
||||
ax.add_artist(plt.Rectangle((-1, -0.5), 2, 1, color=s.colors['black']))
|
||||
ax.harrow(1.6, 0, 1.3, **s.asLine)
|
||||
ax.set_xlim(-6, 14)
|
||||
ax.set_ylim(-1, 1)
|
||||
if f1 is None and f2 is None:
|
||||
ax.text(3.5, 0, '$r$', va='center')
|
||||
else:
|
||||
ax.harrow(-2.8, 0, 1.3, **s.asLine)
|
||||
if f2 is None:
|
||||
ax.text(-3.2, 0, '$s_1(t)$', ha='right', va='center')
|
||||
ax.text(3.3, 0, '$r + r_1(t)$', va='center')
|
||||
elif f1 is None:
|
||||
ax.text(-3.2, 0, '$s_2(t)$', ha='right', va='center')
|
||||
ax.text(3.3, 0, '$r + r_2(t)$', va='center')
|
||||
else:
|
||||
ax.text(-3.2, 0, '$s_1(t) + s_2(t)$', ha='right', va='center')
|
||||
ax.text(3.3, 0, '$\\ne r + r_1(t) + r_2(t)$', va='center')
|
||||
|
||||
|
||||
def plot_stimulus(ax, s, tmax, eodf, f1, f2, c=0.1):
|
||||
def plot_stimulus(ax, s, tmax, eodf, freqs, c=0.1):
|
||||
time = np.arange(0, tmax, 0.0001)
|
||||
eod = np.cos(2*np.pi*eodf*time)
|
||||
am = np.ones(len(time))
|
||||
ams = {}
|
||||
f1, f2 = freqs
|
||||
label = '$f_{EOD}$'
|
||||
if f1 is not None:
|
||||
eod += c*np.cos(2*np.pi*(eodf + f1)*time)
|
||||
am += c*np.cos(2*np.pi*f1*time)
|
||||
ams = s.lsF01
|
||||
ams = s.lsF02
|
||||
label += r' \& $f_1$'
|
||||
if f2 is not None:
|
||||
eod += c*np.cos(2*np.pi*(eodf + f2)*time)
|
||||
am += c*np.cos(2*np.pi*f2*time)
|
||||
ams = s.lsF02
|
||||
ams = s.lsF01
|
||||
label += r' \& $f_2$'
|
||||
if f1 is not None and f2 is not None:
|
||||
ams = s.lsF012
|
||||
ams = s.lsF01_2
|
||||
ax.show_spines('')
|
||||
ax.plot(1000*time, am*eod, **s.lsStim)
|
||||
ax.plot(1000*time, eod, **s.lsEOD)
|
||||
if len(ams) > 0:
|
||||
ax.plot(1000*time, am, **ams)
|
||||
ax.set_xlim(0, 1000*tmax)
|
||||
ax.set_ylim(-1.02 - 2*c, 1.02 + 2*c)
|
||||
ax.text(0, 1.1, label, transform=ax.transAxes)
|
||||
ax.text(0.5, 1.2, label, ha='center', transform=ax.transAxes)
|
||||
|
||||
|
||||
def plot_raster(ax, s, spikes, tmin, tmax):
|
||||
spikes_ms = [1000*(s[(s > tmin) & (s < tmax)] - tmin) for s in spikes]
|
||||
ax.show_spines('')
|
||||
ax.eventplot(spikes_ms, linelengths=0.9, **s.lsRaster)
|
||||
ax.eventplot(spikes_ms, linelengths=0.8, **s.lsRaster)
|
||||
ax.set_xlim(0, 1000*(tmax - tmin))
|
||||
|
||||
|
||||
@ -123,71 +242,89 @@ def plot_rate(ax, s, spikes, tmin, tmax, sigma=0.002):
|
||||
ax.show_spines('')
|
||||
ax.plot(1000*time, r, **s.lsRate)
|
||||
ax.set_xlim(0, 1000*(tmax - tmin))
|
||||
ax.set_ylim(0, 500)
|
||||
ax.set_ylim(-10, 550)
|
||||
|
||||
|
||||
def plot_psd(ax, s, spikes, tmax, fmax, dt=0.0005, nfft=512):
|
||||
time = np.arange(0, tmax, dt)
|
||||
if nfft > len(time):
|
||||
print('nfft too large:', nfft, len(time))
|
||||
# power spectrum:
|
||||
freqs = np.fft.fftfreq(nfft, dt)
|
||||
freqs = np.fft.fftshift(freqs)
|
||||
f0 = len(freqs)//4
|
||||
f1 = 3*len(freqs)//4
|
||||
segments = range(0, len(time) - nfft, nfft)
|
||||
p_rr = np.zeros(len(freqs))
|
||||
n = 0
|
||||
for i, spiket in enumerate(spikes):
|
||||
b, _ = np.histogram(spiket, time)
|
||||
b = b / dt
|
||||
for j, k in enumerate(segments):
|
||||
fourier_r = np.fft.fft(b[k:k + nfft] - np.mean(b), n=nfft)
|
||||
fourier_r = np.fft.fftshift(fourier_r)
|
||||
p_rr += np.abs(fourier_r*np.conj(fourier_r))
|
||||
n += 1
|
||||
freqs = freqs[f0:f1]
|
||||
scale = dt/nfft/n
|
||||
p_rr = p_rr[f0:f1]*scale
|
||||
def plot_psd(ax, s, freqs, power, fmax, dt=0.0005, nfft=512):
|
||||
# plot:
|
||||
mask = (freqs > 0) & (freqs <= fmax)
|
||||
mask = freqs <= fmax
|
||||
freqs = freqs[mask]
|
||||
p_rr = p_rr[mask]
|
||||
#print(np.max(p_rr))
|
||||
p_ref = 4000
|
||||
ax.plot(freqs, 10*np.log10(p_rr/p_ref), **s.lsPower)
|
||||
power = power[mask]
|
||||
ax.show_spines('b')
|
||||
ax.plot(freqs, power, **s.lsPower)
|
||||
ax.set_xlim(0, fmax)
|
||||
ax.set_ylim(-20, 0)
|
||||
ax.set_xlabel('Frequency', 'Hz')
|
||||
|
||||
|
||||
def mark_freq(ax, freqs, power, f, label, style, xoffs=10, yoffs=0, toffs=0, angle=0):
|
||||
i = np.argmin(np.abs(freqs - abs(f)))
|
||||
p = power[i]
|
||||
f = freqs[i]
|
||||
ax.plot(f, p + 1 + yoffs, clip_on=False, **style)
|
||||
if label:
|
||||
yoffs += 3 + toffs
|
||||
if angle > 0:
|
||||
yoffs -= 1
|
||||
ax.text(f - xoffs, p + yoffs, label, color=style['color'], rotation=angle)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
spikes, eodf, df1, df2, t0, t1, t2, t12 = load_data(data_path / cell)
|
||||
print(f'Loaded spike data for cell {cell}: ')
|
||||
spikes, eodf, df1, df2, t0, t1, t2, t12, index = load_spikes(data_path / cell)
|
||||
print(f'Loaded spike data for cell {cell} @ index {index}:')
|
||||
print(f' EODf = {eodf:.1f}Hz')
|
||||
print(f' Df1 = {df1:.1f}Hz')
|
||||
print(f' Df2 = {df2:.1f}Hz')
|
||||
print(f' {len(spikes)} trials')
|
||||
|
||||
print(f'Load AMs for cell {cell} @ index {index}:')
|
||||
ams = load_am(data_path / cell, index)
|
||||
|
||||
phases = am_phases(ams, eodf, df1, df2, t1, t2, t12)
|
||||
|
||||
s = plot_style()
|
||||
fig, axs = plt.subplots(5, 4, cmsize=(s.plot_width, 0.6*s.plot_width),
|
||||
height_ratios=[1, 2, 1, 3, 6])
|
||||
height_ratios=[1, 0, 2, 1.3, 3, 0.7, 5])
|
||||
fig.subplots_adjust(leftm=3, rightm=4.5, topm=1.5, bottomm=4, wspace=0.4, hspace=0.4)
|
||||
fmax = 250
|
||||
tmin = 0.1
|
||||
tmax = 0.2
|
||||
tmin = 0.106
|
||||
tmax = 0.206
|
||||
twins = [[-t0, 0], [t1, t1 + t2], [0, t1], [t1 + t2, t1 + t2 + t12]]
|
||||
freqs = [eodf, df2, df1, df2]
|
||||
stim_freqs = [[None, None], [df2, None], [None, df1], [df1, df2]]
|
||||
stim_phases = [[None, None], [phases[:, 1], None], [None, phases[:, 0]], [phases[:, 2], phases[:, 3]]]
|
||||
base_rate = baseline_rate(spikes, *twins[0])
|
||||
print(f'Baseline firing rate: {base_rate:.1f}Hz')
|
||||
powers = []
|
||||
for i in range(axs.shape[1]):
|
||||
tstart, tend = twins[i]
|
||||
plot_symbols(axs[0, i], s)
|
||||
plot_stimulus(axs[1, i], s, tmax - tmin, eodf, *stim_freqs[i])
|
||||
plot_symbols(axs[0, i], s, stim_freqs[i])
|
||||
plot_stimulus(axs[1, i], s, tmax - tmin, eodf, stim_freqs[i])
|
||||
sub_spikes = [times[(times >= tstart) & (times <= tend)] - tstart for times in spikes]
|
||||
plot_psd(axs[4, i], s, sub_spikes, tend - tstart, fmax)
|
||||
print(f'align spikes for frequency {freqs[i]:.0f}Hz:')
|
||||
sub_spikes = align_spikes(sub_spikes, abs(1/freqs[i]))
|
||||
freqs, power = power_spectrum(sub_spikes, tend - tstart)
|
||||
powers.append(power)
|
||||
plot_psd(axs[4, i], s, freqs, power, fmax)
|
||||
sub_spikes = align_spikes(sub_spikes, stim_freqs[i], stim_phases[i])
|
||||
plot_raster(axs[2, i], s, sub_spikes, tmin, tmax)
|
||||
plot_rate(axs[3, i], s, sub_spikes, tmin, tmax)
|
||||
#fig.savefig()
|
||||
plt.show()
|
||||
mark_freq(axs[4, 0], freqs, powers[0], base_rate, f'$r={base_rate:.0f}$\\,Hz', s.psF0, 30)
|
||||
mark_freq(axs[4, 1], freqs, powers[1], df2, f'$\\Delta f_1=f_1 - f_{{EOD}}={abs(df2):.0f}$\\,Hz', s.psF02)
|
||||
mark_freq(axs[4, 1], freqs, powers[1], 2*df2, f'$2\\Delta f_1={abs(2*df2):.0f}$\\,Hz', s.psF02)
|
||||
mark_freq(axs[4, 2], freqs, powers[2], df1, '', s.psF0)
|
||||
mark_freq(axs[4, 2], freqs, powers[2], df1, f'$\\Delta f_2=f_2 - f_{{EOD}}={abs(df1):.0f}$\\,Hz',
|
||||
s.psF01, 130, 1.5)
|
||||
mark_freq(axs[4, 3], freqs, powers[3], df2, '', s.psF02)
|
||||
mark_freq(axs[4, 3], freqs, powers[3], 2*df2, '', s.psF02)
|
||||
mark_freq(axs[4, 3], freqs, powers[3], df1, '', s.psF0)
|
||||
mark_freq(axs[4, 3], freqs, powers[3], df1, '', s.psF01, 130, 1.5)
|
||||
mark_freq(axs[4, 3], freqs, powers[3], abs(df1) + abs(df2) - 2,
|
||||
f'$\\Delta f_1 + \\Delta f_2={abs(df1) + abs(df2):.0f}$\\,Hz', s.psF012, 20, angle=40)
|
||||
mark_freq(axs[4, 3], freqs, powers[3], abs(df1) - abs(df2),
|
||||
f'$\\Delta f_1 + \\Delta f_2={abs(df1) - abs(df2):.0f}$\\,Hz', s.psF01_2, 50, toffs=5, angle=40)
|
||||
axs[3, 0].scalebars(-0.03, 0, 20, 500, 'ms', 'Hz')
|
||||
axs[4, 0].yscalebar(-0.03, 0.5, 10, 'dB', va='center')
|
||||
#fig.tag(axs.T)
|
||||
fig.tag(axs[0])
|
||||
fig.savefig()
|
||||
#plt.show()
|
||||
print()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user