spikertools 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,232 @@
1
+ Metadata-Version: 2.4
2
+ Name: spikertools
3
+ Version: 0.1.0
4
+ Summary: A Python library for neuroscience data analysis of Backyard Brains SpikeRecorder files - forked from Backyard Brains github
5
+ Home-page: https://github.com/LeonardoFerrisi/SpikerTools
6
+ Author: Greg Gage
7
+ Author-email: gagegreg@backyardbrains.com
8
+ Maintainer: Leonardo Ferrisi
9
+ Maintainer-email: Leonardo.Ferrisi@utah.edu
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Topic :: Scientific/Engineering
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ Requires-Dist: numpy
21
+ Requires-Dist: scipy
22
+ Requires-Dist: matplotlib
23
+ Requires-Dist: seaborn
24
+ Dynamic: author
25
+ Dynamic: author-email
26
+ Dynamic: classifier
27
+ Dynamic: description
28
+ Dynamic: description-content-type
29
+ Dynamic: home-page
30
+ Dynamic: maintainer
31
+ Dynamic: maintainer-email
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
35
+
36
+ # SpikerTools
37
+
38
+ **SpikerTools** is a Python library designed to help students analyze SpikeRecorder files from SpikerBoxes. It provides easy-to-use functions for loading, processing, and visualizing neural and EEG data, enabling students to explore neuroscience concepts through hands-on data analysis.
39
+
40
+ ## Table of Contents
41
+
42
+ - [Features](#features)
43
+ - [Installation](#installation)
44
+ - [Getting Started](#getting-started)
45
+ - [Usage Examples](#usage-examples)
46
+ - [Loading Data](#loading-data)
47
+ - [Plotting Session Overview](#plotting-session-overview)
48
+ - [Event-Related Potential (ERP)](#event-related-potential-erp)
49
+ - [Peri-Event Time Histogram (PETH)](#peri-event-time-histogram-peth)
50
+ - [Spectrogram Analysis](#spectrogram-analysis)
51
+ - [Average Power Spectrum](#average-power-spectrum)
52
+ - [For Teachers](#for-teachers)
53
+ - [Sample Lesson Plan](#sample-lesson-plan)
54
+ - [Contributing](#contributing)
55
+ - [License](#license)
56
+
57
+ ## Features
58
+
59
+ - Load neural and EEG data from WAV files.
60
+ - Handle events and neuronal spikes with timestamped annotations.
61
+ - Filter and normalize signal data.
62
+ - Compute statistical measures like inter-spike intervals and firing rates.
63
+ - Visualize data with various plots:
64
+ - Session overview with event markers.
65
+ - Event-Related Potentials (ERPs).
66
+ - Peri-Event Time Histograms (PETH) with raster plots.
67
+ - Spectrograms with event overlays.
68
+ - Average power spectra for frequency analysis.
69
+ - Histograms of inter-event and inter-spike intervals.
70
+
71
+ ## Installation
72
+
73
+ You can install SpikerTools using pip:
74
+
75
+ ```bash
76
+ pip install spikertools
77
+ ```
78
+
79
+ Note: If SpikerTools is not yet available on PyPI, you can install it directly from the source code:
80
+
81
+ ```bash
82
+ git clone https://github.com/BackyardBrains/SpikerTools.git
83
+ pip install -e ./SpikerTools
84
+ ```
85
+ ### If you are in a jupyter notebook
86
+ ```bash
87
+ !pip install ./Spikertools
88
+ ```
89
+
90
+ ## Getting Started
91
+
92
+ ### Prerequisites
93
+
94
+ - Python 3.6 or higher
95
+ - Required Python packages:
96
+ - numpy
97
+ - scipy
98
+ - matplotlib
99
+ - seaborn
100
+
101
+ Install the required packages using:
102
+
103
+ ```bash
104
+ pip install numpy scipy matplotlib seaborn
105
+ ```
106
+
107
+ ## Usage Examples
108
+
109
+ ### Loading Data
110
+
111
+ ```python
112
+ from spikertools import Session
113
+
114
+ # Load your data file (WAV file and corresponding events file)
115
+ wav_file_path = 'data/neurons/rate_coding/BYB_Recording_2022-01-13_13.18.29.wav'
116
+
117
+ # Initialize the Session
118
+ session = Session(wav_file_path)
119
+ ```
120
+
121
+ ### Plotting Channels from Session
122
+
123
+ ```python
124
+ # Plot the session overview with event markers
125
+ session.plots.plot_channels()
126
+ ```
127
+
128
+ ### Event-Related Potential (ERP)
129
+
130
+ ```python
131
+
132
+ p300_wav_file = 'data/eeg/p300/BYB_Recording_2019-06-11_13.23.58.wav'
133
+ s = Session(p300_wav_file)
134
+
135
+ # Define events for P300 (default is '1' and '2') and add colors
136
+ s.events[0].name = 'standard'
137
+ s.events[0].color = 'blue'
138
+
139
+ s.events[1].name = 'oddball'
140
+ s.events[1].color = 'red'
141
+
142
+ # Assign location as name to the P300 channel (Optional)
143
+ s.channels[0].name = 'P4'
144
+
145
+ # Optional: Filter the P300 channel to reduce high frequency noise
146
+ s.channels[0].filter(ftype='lp', cutoff=10, order=3)
147
+ ```
148
+
149
+ ### Peri-Event Time Histogram (PETH)
150
+
151
+ ```python
152
+ # Plot PETH with raster for a neuron aligned to an event
153
+ session.plots.plot_peth(
154
+ neuron=s.neurons[0], # Neuron to plot (defaults to first)
155
+ events=s.events, # List of Event objects (defaults to all)
156
+ epoch_window=(-0.5, 1.0), # 500ms before to 1000ms after event
157
+ bin_size=0.04, # 40ms bins
158
+ title="Peri-Event Time Histogram (PETH) with Raster Plots for Touch Pressure Events", # Add a custom title
159
+ save_path=None, # Save the plot to a file
160
+ show=True
161
+ )
162
+ ```
163
+
164
+ ### Spectrogram Analysis
165
+
166
+ ```python
167
+ # Plot spectrogram of the EEG data with event markers
168
+ session.plots.plot_spectrogram(
169
+ channel=session.channels[0],
170
+ freq_range=(0, 50),
171
+ events=session.events
172
+ )
173
+ ```
174
+
175
+ ### Average Power Spectrum
176
+
177
+ ```python
178
+ # Plot average power spectra during 'Open' and 'Close' events
179
+ session.plots.plot_average_power(
180
+ events=session.events,
181
+ freq_range=(0, 30),
182
+ epoch_window=(0, 5),
183
+ channel=session.channels[0]
184
+ )
185
+ ```
186
+
187
+ ## For Teachers
188
+
189
+ SpikerTools is designed to be an educational tool that integrates seamlessly into classroom activities. Here's how you can incorporate it into your teaching:
190
+
191
+ - **Hands-On Data Analysis**: Provide students with real neural or EEG data recordings and guide them through loading and analyzing the data using SpikerTools.
192
+ - **Visualization of Neural Activity**: Use the plotting functions to help students visualize neural spikes, event-related potentials, and frequency content of EEG signals.
193
+ - **Concept Reinforcement**: Reinforce concepts like neuronal firing rates, inter-spike intervals, and the effects of stimuli on neural activity.
194
+ - **Customizable Plots**: Encourage students to explore different parameters and customize plots to deepen their understanding.
195
+ - **Interdisciplinary Learning**: Integrate programming skills with neuroscience, promoting interdisciplinary education.
196
+
197
+ ### Sample Lesson Plan
198
+
199
+ 1. **Introduction to Neural Signals:**
200
+ - Discuss the basics of neural spikes and EEG signals.
201
+ - Explain the significance of events and stimuli in neural recordings.
202
+
203
+ 2. **Data Loading and Preprocessing:**
204
+ - Show students how to load data into SpikerTools.
205
+ - Demonstrate filtering and normalization techniques.
206
+
207
+ 3. **Data Visualization:**
208
+ - Guide students through plotting session overviews and ERPs.
209
+ - Analyze spectrograms to understand frequency components.
210
+
211
+ 4. **Data Analysis:**
212
+ - Calculate firing rates and inter-spike intervals.
213
+ - Compare neural responses to different stimuli.
214
+
215
+ 5. **Discussion and Interpretation:**
216
+ - Interpret the results and discuss their implications.
217
+ - Encourage students to ask questions and explore further.
218
+
219
+ ## Contributing
220
+
221
+ We welcome contributions to enhance SpikerTools. If you have ideas for new features, improvements, or bug fixes, please:
222
+
223
+ 1. Fork the repository.
224
+ 2. Create a new branch for your feature or fix.
225
+ 3. Commit your changes with clear messages.
226
+ 4. Submit a pull request describing your changes.
227
+
228
+ Please ensure that your code follows best practices and includes appropriate tests.
229
+
230
+ ## License
231
+
232
+ SpikerTools is released under the **MIT License**.
@@ -0,0 +1,197 @@
1
+ # SpikerTools
2
+
3
+ **SpikerTools** is a Python library designed to help students analyze SpikeRecorder files from SpikerBoxes. It provides easy-to-use functions for loading, processing, and visualizing neural and EEG data, enabling students to explore neuroscience concepts through hands-on data analysis.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Features](#features)
8
+ - [Installation](#installation)
9
+ - [Getting Started](#getting-started)
10
+ - [Usage Examples](#usage-examples)
11
+ - [Loading Data](#loading-data)
12
+ - [Plotting Session Overview](#plotting-session-overview)
13
+ - [Event-Related Potential (ERP)](#event-related-potential-erp)
14
+ - [Peri-Event Time Histogram (PETH)](#peri-event-time-histogram-peth)
15
+ - [Spectrogram Analysis](#spectrogram-analysis)
16
+ - [Average Power Spectrum](#average-power-spectrum)
17
+ - [For Teachers](#for-teachers)
18
+ - [Sample Lesson Plan](#sample-lesson-plan)
19
+ - [Contributing](#contributing)
20
+ - [License](#license)
21
+
22
+ ## Features
23
+
24
+ - Load neural and EEG data from WAV files.
25
+ - Handle events and neuronal spikes with timestamped annotations.
26
+ - Filter and normalize signal data.
27
+ - Compute statistical measures like inter-spike intervals and firing rates.
28
+ - Visualize data with various plots:
29
+ - Session overview with event markers.
30
+ - Event-Related Potentials (ERPs).
31
+ - Peri-Event Time Histograms (PETH) with raster plots.
32
+ - Spectrograms with event overlays.
33
+ - Average power spectra for frequency analysis.
34
+ - Histograms of inter-event and inter-spike intervals.
35
+
36
+ ## Installation
37
+
38
+ You can install SpikerTools using pip:
39
+
40
+ ```bash
41
+ pip install spikertools
42
+ ```
43
+
44
+ Note: If SpikerTools is not yet available on PyPI, you can install it directly from the source code:
45
+
46
+ ```bash
47
+ git clone https://github.com/BackyardBrains/SpikerTools.git
48
+ pip install -e ./SpikerTools
49
+ ```
50
+ ### If you are in a jupyter notebook
51
+ ```bash
52
+ !pip install ./Spikertools
53
+ ```
54
+
55
+ ## Getting Started
56
+
57
+ ### Prerequisites
58
+
59
+ - Python 3.6 or higher
60
+ - Required Python packages:
61
+ - numpy
62
+ - scipy
63
+ - matplotlib
64
+ - seaborn
65
+
66
+ Install the required packages using:
67
+
68
+ ```bash
69
+ pip install numpy scipy matplotlib seaborn
70
+ ```
71
+
72
+ ## Usage Examples
73
+
74
+ ### Loading Data
75
+
76
+ ```python
77
+ from spikertools import Session
78
+
79
+ # Load your data file (WAV file and corresponding events file)
80
+ wav_file_path = 'data/neurons/rate_coding/BYB_Recording_2022-01-13_13.18.29.wav'
81
+
82
+ # Initialize the Session
83
+ session = Session(wav_file_path)
84
+ ```
85
+
86
+ ### Plotting Channels from Session
87
+
88
+ ```python
89
+ # Plot the session overview with event markers
90
+ session.plots.plot_channels()
91
+ ```
92
+
93
+ ### Event-Related Potential (ERP)
94
+
95
+ ```python
96
+
97
+ p300_wav_file = 'data/eeg/p300/BYB_Recording_2019-06-11_13.23.58.wav'
98
+ s = Session(p300_wav_file)
99
+
100
+ # Define events for P300 (default is '1' and '2') and add colors
101
+ s.events[0].name = 'standard'
102
+ s.events[0].color = 'blue'
103
+
104
+ s.events[1].name = 'oddball'
105
+ s.events[1].color = 'red'
106
+
107
+ # Assign location as name to the P300 channel (Optional)
108
+ s.channels[0].name = 'P4'
109
+
110
+ # Optional: Filter the P300 channel to reduce high frequency noise
111
+ s.channels[0].filter(ftype='lp', cutoff=10, order=3)
112
+ ```
113
+
114
+ ### Peri-Event Time Histogram (PETH)
115
+
116
+ ```python
117
+ # Plot PETH with raster for a neuron aligned to an event
118
+ session.plots.plot_peth(
119
+ neuron=s.neurons[0], # Neuron to plot (defaults to first)
120
+ events=s.events, # List of Event objects (defaults to all)
121
+ epoch_window=(-0.5, 1.0), # 500ms before to 1000ms after event
122
+ bin_size=0.04, # 40ms bins
123
+ title="Peri-Event Time Histogram (PETH) with Raster Plots for Touch Pressure Events", # Add a custom title
124
+ save_path=None, # Save the plot to a file
125
+ show=True
126
+ )
127
+ ```
128
+
129
+ ### Spectrogram Analysis
130
+
131
+ ```python
132
+ # Plot spectrogram of the EEG data with event markers
133
+ session.plots.plot_spectrogram(
134
+ channel=session.channels[0],
135
+ freq_range=(0, 50),
136
+ events=session.events
137
+ )
138
+ ```
139
+
140
+ ### Average Power Spectrum
141
+
142
+ ```python
143
+ # Plot average power spectra during 'Open' and 'Close' events
144
+ session.plots.plot_average_power(
145
+ events=session.events,
146
+ freq_range=(0, 30),
147
+ epoch_window=(0, 5),
148
+ channel=session.channels[0]
149
+ )
150
+ ```
151
+
152
+ ## For Teachers
153
+
154
+ SpikerTools is designed to be an educational tool that integrates seamlessly into classroom activities. Here's how you can incorporate it into your teaching:
155
+
156
+ - **Hands-On Data Analysis**: Provide students with real neural or EEG data recordings and guide them through loading and analyzing the data using SpikerTools.
157
+ - **Visualization of Neural Activity**: Use the plotting functions to help students visualize neural spikes, event-related potentials, and frequency content of EEG signals.
158
+ - **Concept Reinforcement**: Reinforce concepts like neuronal firing rates, inter-spike intervals, and the effects of stimuli on neural activity.
159
+ - **Customizable Plots**: Encourage students to explore different parameters and customize plots to deepen their understanding.
160
+ - **Interdisciplinary Learning**: Integrate programming skills with neuroscience, promoting interdisciplinary education.
161
+
162
+ ### Sample Lesson Plan
163
+
164
+ 1. **Introduction to Neural Signals:**
165
+ - Discuss the basics of neural spikes and EEG signals.
166
+ - Explain the significance of events and stimuli in neural recordings.
167
+
168
+ 2. **Data Loading and Preprocessing:**
169
+ - Show students how to load data into SpikerTools.
170
+ - Demonstrate filtering and normalization techniques.
171
+
172
+ 3. **Data Visualization:**
173
+ - Guide students through plotting session overviews and ERPs.
174
+ - Analyze spectrograms to understand frequency components.
175
+
176
+ 4. **Data Analysis:**
177
+ - Calculate firing rates and inter-spike intervals.
178
+ - Compare neural responses to different stimuli.
179
+
180
+ 5. **Discussion and Interpretation:**
181
+ - Interpret the results and discuss their implications.
182
+ - Encourage students to ask questions and explore further.
183
+
184
+ ## Contributing
185
+
186
+ We welcome contributions to enhance SpikerTools. If you have ideas for new features, improvements, or bug fixes, please:
187
+
188
+ 1. Fork the repository.
189
+ 2. Create a new branch for your feature or fix.
190
+ 3. Commit your changes with clear messages.
191
+ 4. Submit a pull request describing your changes.
192
+
193
+ Please ensure that your code follows best practices and includes appropriate tests.
194
+
195
+ ## License
196
+
197
+ SpikerTools is released under the **MIT License**.
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,39 @@
1
+ # setup.py
2
+
3
+ from pathlib import Path
4
+
5
+ from setuptools import setup, find_packages
6
+
7
+ long_description = Path(__file__).parent.joinpath("README.md").read_text(encoding="utf-8")
8
+
9
+ setup(
10
+ name='spikertools',
11
+ version='0.1.0',
12
+ packages=find_packages(),
13
+ install_requires=[
14
+ 'numpy',
15
+ 'scipy',
16
+ 'matplotlib',
17
+ 'seaborn',
18
+ ],
19
+ python_requires='>=3.9',
20
+ include_package_data=True,
21
+ description='A Python library for neuroscience data analysis of Backyard Brains SpikeRecorder files - forked from Backyard Brains github',
22
+ long_description=long_description,
23
+ long_description_content_type='text/markdown',
24
+ author='Greg Gage',
25
+ author_email='gagegreg@backyardbrains.com',
26
+ maintainer='Leonardo Ferrisi',
27
+ maintainer_email='Leonardo.Ferrisi@utah.edu',
28
+ url='https://github.com/LeonardoFerrisi/SpikerTools',
29
+ classifiers=[
30
+ 'Programming Language :: Python :: 3',
31
+ 'Programming Language :: Python :: 3.9',
32
+ 'Programming Language :: Python :: 3.10',
33
+ 'Programming Language :: Python :: 3.11',
34
+ 'Programming Language :: Python :: 3.12',
35
+ 'Operating System :: OS Independent',
36
+ 'Intended Audience :: Science/Research',
37
+ 'Topic :: Scientific/Engineering',
38
+ ],
39
+ )
@@ -0,0 +1,7 @@
1
+ # spikertools/__init__.py
2
+
3
+ from .models import Event
4
+ from .core import Session, Channel, Neuron, Events
5
+ from .plots import Plots
6
+
7
+ __all__ = ['Session', 'Channel', 'Event', 'Neuron', 'Events', 'Plots']
@@ -0,0 +1,149 @@
1
+ # spikertools/core.py
2
+
3
+ from spikertools.models import Event, Neuron, Channel, Session, Events, Channels
4
+ from spikertools.plots import Plots
5
+ import numpy as np
6
+ from scipy.io import wavfile
7
+ import os
8
+ import re
9
+ from datetime import datetime
10
+
11
+ class Session:
12
+ def __init__(self, wav_file_path, events_file_path=None):
13
+ self.wav_file = wav_file_path
14
+ self.sample_rate, self.data = wavfile.read(wav_file_path)
15
+ print(f"Loaded WAV file: {wav_file_path}")
16
+ print(f"Sample rate: {self.sample_rate} Hz")
17
+ print(f"Data length: {len(self.data)} samples")
18
+
19
+ if events_file_path is None:
20
+ # Infer events file path
21
+ events_file = wav_file_path.replace('.wav', '-events.txt')
22
+ else:
23
+ events_file = events_file_path
24
+
25
+ print(f"Looking for events file: {events_file}")
26
+
27
+ # Initialize events and neurons before loading
28
+ self.events = Events([]) # Changed from list to Events
29
+ self.neurons = []
30
+
31
+ # Initialize the Plots class
32
+ self.plots = Plots(self)
33
+
34
+ if os.path.exists(events_file):
35
+ self._load_events(events_file)
36
+ print(f"Loaded {len(self.events)} events and {len(self.neurons)} neurons.")
37
+ else:
38
+ print("No events file found.")
39
+
40
+ # Initialize other attributes
41
+ self.channels = self._initialize_channels()
42
+ self.datetime = self._extract_datetime()
43
+
44
+ def _load_events(self, events_file):
45
+ with open(events_file, 'r') as f:
46
+ for line in f:
47
+ line = line.strip()
48
+ if not line or line.startswith('#'):
49
+ continue
50
+ parts = line.split(',')
51
+ if len(parts) != 2:
52
+ continue
53
+ name, timestamp = parts
54
+ name = name.strip()
55
+ try:
56
+ timestamp = float(timestamp.strip())
57
+ except ValueError:
58
+ print(f"Invalid timestamp: {timestamp} in line: {line}")
59
+ continue
60
+ self._add_event(name, timestamp)
61
+
62
+ def _add_event(self, name, timestamp):
63
+ # Normalize the event name by stripping leading/trailing spaces
64
+ name = name.strip()
65
+
66
+ # Assign colors to events and neurons
67
+ color = 'k' # Default color is black
68
+ color_map = {
69
+ '1': 'r', '2': 'g', '3': 'b', '4': 'c', '5': 'm',
70
+ 'Open': 'orange', 'Close': 'purple',
71
+ }
72
+ if name in color_map:
73
+ color = color_map[name]
74
+
75
+ # Check if event already exists
76
+ if self.events.has_event(name):
77
+ self.events[name].timestamps.append(timestamp)
78
+ return
79
+
80
+ # Handle threshold events for neurons
81
+ if 'thresh' in name.lower():
82
+ # Use regex to parse threshold events
83
+ match = re.match(r'_(neuron\d+)thresh(\w+)-(\d+)', name, re.IGNORECASE)
84
+ if match:
85
+ neuron_id, thresh_type_partial, thresh_value_str = match.groups()
86
+ thresh_value = -int(thresh_value_str) # Assuming thresholds are negative
87
+
88
+ # Find the neuron that corresponds to this threshold
89
+ target_neuron = None
90
+ for neuron in self.neurons:
91
+ if neuron_id in neuron.name:
92
+ target_neuron = neuron
93
+ break
94
+
95
+ if target_neuron:
96
+ if 'hig' in thresh_type_partial.lower():
97
+ target_neuron.thresh_high = thresh_value
98
+ #print(f"Set high threshold for {target_neuron.name} to {thresh_value}")
99
+ elif 'low' in thresh_type_partial.lower():
100
+ target_neuron.thresh_low = thresh_value
101
+ #print(f"Set low threshold for {target_neuron.name} to {thresh_value}")
102
+ else:
103
+ print(f"Unknown threshold type in event name: {name}")
104
+ else:
105
+ print(f"Neuron '{neuron_id}' not found for threshold event: {name}")
106
+ return # Threshold event processed; exit the method
107
+
108
+ # Check if neuron already exists for spike events
109
+ if name.startswith('_'):
110
+ for neuron in self.neurons:
111
+ if neuron.name == name:
112
+ neuron.timestamps.append(timestamp)
113
+ return
114
+
115
+ # If not, create a new neuron
116
+ neuron = Neuron(name, timestamps=[timestamp], color=color)
117
+ self.neurons.append(neuron)
118
+ #print(f"Added neuron: '{name}' with initial spike at timestamp: {timestamp}")
119
+ else:
120
+ # If not a neuron, treat as a regular event
121
+ event = Event(name, timestamps=[timestamp], color=color)
122
+ self.events.append(event)
123
+ #print(f"Added event: '{name}' at timestamp: {timestamp}")
124
+
125
+ def _initialize_channels(self):
126
+ # Initialize channels based on the data
127
+ channels = Channels([]) # Initialize empty Channels container (this uses models.Channels)
128
+ if self.data.ndim == 1:
129
+ channel = Channel(self.data, sample_rate=self.sample_rate, number=0) # This will now use models.Channel
130
+ channels.append(channel)
131
+ else:
132
+ for i in range(self.data.shape[1]):
133
+ channel_data = self.data[:, i]
134
+ channel = Channel(channel_data, sample_rate=self.sample_rate, number=i) # This will now use models.Channel
135
+ channels.append(channel)
136
+ return channels
137
+
138
+ def _extract_datetime(self):
139
+ # Extract datetime from the filename
140
+ basename = os.path.basename(self.wav_file)
141
+ match = re.search(r'(\d{4}-\d{2}-\d{2})_(\d{2}\.\d{2}\.\d{2})', basename)
142
+ if match:
143
+ date_str, time_str = match.groups()
144
+ date_parts = [int(part) for part in date_str.split('-')]
145
+ time_parts = [int(part) for part in time_str.split('.')]
146
+ return datetime(*date_parts, *time_parts)
147
+ return None
148
+
149
+