lab1tools 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.
- lab1tools-0.1.0/PKG-INFO +9 -0
- lab1tools-0.1.0/README.md +0 -0
- lab1tools-0.1.0/pyproject.toml +17 -0
- lab1tools-0.1.0/src/lab1tools/.ipynb_checkpoints/__init__-checkpoint.py +3 -0
- lab1tools-0.1.0/src/lab1tools/.ipynb_checkpoints/functions-checkpoint.py +68 -0
- lab1tools-0.1.0/src/lab1tools/__init__.py +3 -0
- lab1tools-0.1.0/src/lab1tools/functions.py +68 -0
lab1tools-0.1.0/PKG-INFO
ADDED
|
File without changes
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "lab1tools"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Tools used in the first lab of Astron121."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "LeoIntril", email = "leo_intriligator@berkeley.edu" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
dependencies = []
|
|
11
|
+
|
|
12
|
+
[project.scripts]
|
|
13
|
+
lab1tools = "lab1tools:main"
|
|
14
|
+
|
|
15
|
+
[build-system]
|
|
16
|
+
requires = ["uv_build>=0.10.0,<0.11.0"]
|
|
17
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import re
|
|
5
|
+
from scipy.signal import correlate
|
|
6
|
+
from scipy.stats import norm
|
|
7
|
+
|
|
8
|
+
def freq_from_filename(fname):
|
|
9
|
+
match = re.search(r"([\d\.]+)Hz", fname)
|
|
10
|
+
if match is None:
|
|
11
|
+
raise ValueError(f"Could not extract frequency from {fname}")
|
|
12
|
+
return float(match.group(1)) # Hz
|
|
13
|
+
|
|
14
|
+
def compute_period(y, fs):
|
|
15
|
+
y = y - np.mean(y) # remove DC
|
|
16
|
+
# Find zero crossings (sign change)
|
|
17
|
+
zero_crossings = np.where(np.diff(np.sign(y)) > 0)[0] # positive-going
|
|
18
|
+
if len(zero_crossings) < 2:
|
|
19
|
+
return None # cannot compute period
|
|
20
|
+
# Compute periods in samples
|
|
21
|
+
periods_samples = np.diff(zero_crossings)
|
|
22
|
+
# Convert to time in seconds
|
|
23
|
+
periods_sec = periods_samples / fs
|
|
24
|
+
return np.mean(periods_sec)
|
|
25
|
+
|
|
26
|
+
def compute_lags(n, fs):
|
|
27
|
+
return np.arange(-n+1, n)/fs
|
|
28
|
+
|
|
29
|
+
def compute_fwhm(x, y):
|
|
30
|
+
"""
|
|
31
|
+
Compute FWHM of a peak in y(x) using linear interpolation.
|
|
32
|
+
Returns NaN if no half-max points are found.
|
|
33
|
+
"""
|
|
34
|
+
y = np.array(y)
|
|
35
|
+
x = np.array(x)
|
|
36
|
+
|
|
37
|
+
y_max = np.max(y)
|
|
38
|
+
half_max = y_max / 2
|
|
39
|
+
|
|
40
|
+
# Indices where y crosses half-max
|
|
41
|
+
indices = np.where(y >= half_max)[0]
|
|
42
|
+
if len(indices) < 2:
|
|
43
|
+
return np.nan # not enough points to define FWHM
|
|
44
|
+
|
|
45
|
+
left_idx = indices[0]
|
|
46
|
+
right_idx = indices[-1]
|
|
47
|
+
|
|
48
|
+
# Linear interpolation for left half-max
|
|
49
|
+
if left_idx == 0:
|
|
50
|
+
x_left = x[0]
|
|
51
|
+
else:
|
|
52
|
+
x1, x2 = x[left_idx-1], x[left_idx]
|
|
53
|
+
y1, y2 = y[left_idx-1], y[left_idx]
|
|
54
|
+
x_left = x1 + (half_max - y1) * (x2 - x1) / (y2 - y1)
|
|
55
|
+
|
|
56
|
+
# Linear interpolation for right half-max
|
|
57
|
+
if right_idx == len(y)-1:
|
|
58
|
+
x_right = x[-1]
|
|
59
|
+
else:
|
|
60
|
+
x1, x2 = x[right_idx], x[right_idx+1]
|
|
61
|
+
y1, y2 = y[right_idx], y[right_idx+1]
|
|
62
|
+
x_right = x1 + (half_max - y1) * (x2 - x1) / (y2 - y1)
|
|
63
|
+
|
|
64
|
+
return x_right - x_left
|
|
65
|
+
|
|
66
|
+
def gaussian(x, A, sigma):
|
|
67
|
+
return A * np.exp(-0.5*(x/sigma)**2)
|
|
68
|
+
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import matplotlib.pyplot as plt
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import re
|
|
5
|
+
from scipy.signal import correlate
|
|
6
|
+
from scipy.stats import norm
|
|
7
|
+
|
|
8
|
+
def freq_from_filename(fname):
|
|
9
|
+
match = re.search(r"([\d\.]+)Hz", fname)
|
|
10
|
+
if match is None:
|
|
11
|
+
raise ValueError(f"Could not extract frequency from {fname}")
|
|
12
|
+
return float(match.group(1)) # Hz
|
|
13
|
+
|
|
14
|
+
def compute_period(y, fs):
|
|
15
|
+
y = y - np.mean(y) # remove DC
|
|
16
|
+
# Find zero crossings (sign change)
|
|
17
|
+
zero_crossings = np.where(np.diff(np.sign(y)) > 0)[0] # positive-going
|
|
18
|
+
if len(zero_crossings) < 2:
|
|
19
|
+
return None # cannot compute period
|
|
20
|
+
# Compute periods in samples
|
|
21
|
+
periods_samples = np.diff(zero_crossings)
|
|
22
|
+
# Convert to time in seconds
|
|
23
|
+
periods_sec = periods_samples / fs
|
|
24
|
+
return np.mean(periods_sec)
|
|
25
|
+
|
|
26
|
+
def compute_lags(n, fs):
|
|
27
|
+
return np.arange(-n+1, n)/fs
|
|
28
|
+
|
|
29
|
+
def compute_fwhm(x, y):
|
|
30
|
+
"""
|
|
31
|
+
Compute FWHM of a peak in y(x) using linear interpolation.
|
|
32
|
+
Returns NaN if no half-max points are found.
|
|
33
|
+
"""
|
|
34
|
+
y = np.array(y)
|
|
35
|
+
x = np.array(x)
|
|
36
|
+
|
|
37
|
+
y_max = np.max(y)
|
|
38
|
+
half_max = y_max / 2
|
|
39
|
+
|
|
40
|
+
# Indices where y crosses half-max
|
|
41
|
+
indices = np.where(y >= half_max)[0]
|
|
42
|
+
if len(indices) < 2:
|
|
43
|
+
return np.nan # not enough points to define FWHM
|
|
44
|
+
|
|
45
|
+
left_idx = indices[0]
|
|
46
|
+
right_idx = indices[-1]
|
|
47
|
+
|
|
48
|
+
# Linear interpolation for left half-max
|
|
49
|
+
if left_idx == 0:
|
|
50
|
+
x_left = x[0]
|
|
51
|
+
else:
|
|
52
|
+
x1, x2 = x[left_idx-1], x[left_idx]
|
|
53
|
+
y1, y2 = y[left_idx-1], y[left_idx]
|
|
54
|
+
x_left = x1 + (half_max - y1) * (x2 - x1) / (y2 - y1)
|
|
55
|
+
|
|
56
|
+
# Linear interpolation for right half-max
|
|
57
|
+
if right_idx == len(y)-1:
|
|
58
|
+
x_right = x[-1]
|
|
59
|
+
else:
|
|
60
|
+
x1, x2 = x[right_idx], x[right_idx+1]
|
|
61
|
+
y1, y2 = y[right_idx], y[right_idx+1]
|
|
62
|
+
x_right = x1 + (half_max - y1) * (x2 - x1) / (y2 - y1)
|
|
63
|
+
|
|
64
|
+
return x_right - x_left
|
|
65
|
+
|
|
66
|
+
def gaussian(x, A, sigma):
|
|
67
|
+
return A * np.exp(-0.5*(x/sigma)**2)
|
|
68
|
+
|