Add first code
This commit is contained in:
parent
fe8e185efb
commit
e530961dd2
4 changed files with 427 additions and 0 deletions
36
pyproject.toml
Normal file
36
pyproject.toml
Normal file
|
@ -0,0 +1,36 @@
|
|||
[project]
|
||||
name = "backscattering-analyzer"
|
||||
version = "0.0.1"
|
||||
authors = [
|
||||
{ name="linarphy", email="linarphy@linarphy.com" },
|
||||
]
|
||||
description = "Analyze backscattering noise"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.8"
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
|
||||
"Intended Audience :: Science/Research",
|
||||
"Operating System :: OS Independent",
|
||||
"Development Status :: 2 - Pre-Alpha",
|
||||
"Topic :: Scientific/Engineering",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://git.linarphy.net/linarphy/backscattering-analyzer"
|
||||
Issues = "https://git.linarphy.net/linarphy/backscattering-analyzer/issues"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/backscattering-analyzer"]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 72
|
||||
|
||||
[tool.ruff.format]
|
||||
quote-style = "double"
|
||||
indent-style = "space"
|
||||
docstring-code-format = true
|
0
src/backscattering-analyzer/__init__.py
Normal file
0
src/backscattering-analyzer/__init__.py
Normal file
245
src/backscattering-analyzer/analyzer.py
Normal file
245
src/backscattering-analyzer/analyzer.py
Normal file
|
@ -0,0 +1,245 @@
|
|||
# display
|
||||
from rich.console import Console
|
||||
from rich.theme import Theme
|
||||
from rich.traceback import install as traceback_install
|
||||
|
||||
# utils
|
||||
from sys import argv as options
|
||||
from settings import Settings
|
||||
from numpy import loadtxt, array
|
||||
from scipy.io.matlab import loadmat
|
||||
|
||||
# maths
|
||||
from numpy import mean, zeros, pi, sin, cos, arange
|
||||
from scipy.signal import welch as psd
|
||||
from scipy.interpolate import CubicSpline
|
||||
|
||||
|
||||
class Analyzer:
|
||||
"""
|
||||
Utility class to study backscattering light in VIRGO
|
||||
"""
|
||||
|
||||
def __init__(self, arguments=[]):
|
||||
self.theme = Theme(
|
||||
{
|
||||
"main": "white bold",
|
||||
"option": "grey50 italic",
|
||||
"argument": "red",
|
||||
"description": "green italic",
|
||||
}
|
||||
)
|
||||
self.console = Console(theme=self.theme)
|
||||
traceback_install(console=self.console, show_locals=True)
|
||||
self.settings = Settings(options[1:] + arguments, self.console)
|
||||
self.load()
|
||||
self.process_movement()
|
||||
|
||||
def load(self):
|
||||
"""
|
||||
Load all data
|
||||
"""
|
||||
if self.settings.verbose:
|
||||
self.console.log("Load all data")
|
||||
try:
|
||||
self.load_bench()
|
||||
self.load_mirror()
|
||||
self.load_data()
|
||||
self.load_reference()
|
||||
self.load_coupling()
|
||||
except Exception:
|
||||
raise Exception("An error occured during data loading")
|
||||
|
||||
def load_bench(self):
|
||||
"""
|
||||
Load bench movement
|
||||
"""
|
||||
file = self.settings.bench_file()
|
||||
if self.settings.verbose:
|
||||
self.console.log("loading bench movement")
|
||||
try:
|
||||
self.bench_movement = loadtxt(file).T
|
||||
except OSError:
|
||||
raise Exception("{file} does not exist".format(file=file))
|
||||
|
||||
def load_mirror(self):
|
||||
"""
|
||||
Load mirror movement
|
||||
"""
|
||||
file = self.settings.mirror_file()
|
||||
if self.settings.verbose:
|
||||
self.console.log("loading mirror movement")
|
||||
try:
|
||||
self.mirror_movement = loadtxt(file).T
|
||||
except OSError:
|
||||
raise Exception("{file} does not exist".format(file=file))
|
||||
|
||||
def load_data(self):
|
||||
"""
|
||||
Load excited h(t)
|
||||
"""
|
||||
file = self.settings.data_file()
|
||||
if self.settings.verbose:
|
||||
self.console.log("loading excited h(t)")
|
||||
try:
|
||||
self.data_signal = loadtxt(file).T
|
||||
except OSError:
|
||||
raise Exception("{file} does not exist".format(file=file))
|
||||
|
||||
def load_reference(self):
|
||||
"""
|
||||
Load reference h(t)
|
||||
"""
|
||||
file = self.settings.reference_file()
|
||||
if self.settings.verbose:
|
||||
self.console.log("loading reference h(t)")
|
||||
try:
|
||||
self.reference_signal = loadtxt(file).T
|
||||
except OSError:
|
||||
raise Exception("{file} does not exist".format(file=file))
|
||||
|
||||
def load_coupling(self):
|
||||
"""
|
||||
Load modelisation coupling data
|
||||
"""
|
||||
file = self.settings.modelisation_file()
|
||||
if self.settings.verbose:
|
||||
self.console.log("loading matlab modelisation data")
|
||||
try:
|
||||
self.modelisation = loadmat(file)
|
||||
except OSError:
|
||||
raise Exception("{file} does not exist".format(file=file))
|
||||
|
||||
def process_movement(self):
|
||||
"""
|
||||
Clean and compute relative movement between the bench and the
|
||||
miror
|
||||
"""
|
||||
if self.settings.verbose:
|
||||
self.console.log("computing relative movement")
|
||||
|
||||
self.movement = array(
|
||||
[
|
||||
self.bench_movement[0],
|
||||
self.bench_movement[1] - self.mirror_movement[1],
|
||||
]
|
||||
)
|
||||
self.movement[1] -= mean(self.movement[1])
|
||||
|
||||
def psd_signal(self, signal, fft_length=10):
|
||||
"""
|
||||
Compute psd of a given signal
|
||||
"""
|
||||
if self.settings.verbose:
|
||||
self.console.log("computing psd of the given signal")
|
||||
rate = 1 / (signal[0, 1] - signal[0, 0])
|
||||
|
||||
return array(
|
||||
psd(
|
||||
signal[1],
|
||||
rate,
|
||||
nperseg=int(fft_length * rate),
|
||||
detrend="linear",
|
||||
)
|
||||
)
|
||||
|
||||
def diff_psd_ref_data(self):
|
||||
"""
|
||||
Give difference between reference and excited signal psd
|
||||
"""
|
||||
if self.settings.verbose:
|
||||
self.console.log(
|
||||
"compute difference between reference and excited "
|
||||
"signal (on the psd)"
|
||||
)
|
||||
freq, data_psd = self.psd_signal(self.data_signal)
|
||||
_, reference_psd = self.psd_signal(self.reference_signal)
|
||||
return array(
|
||||
[
|
||||
freq,
|
||||
data_psd - reference_psd,
|
||||
]
|
||||
)
|
||||
|
||||
def interpolate(self, signals):
|
||||
"""
|
||||
Interpolate multiple signals with a single abciss list, which
|
||||
has the smallest interval and the biggest rate
|
||||
"""
|
||||
rates = 1 / (signals[:, 0, 1] - signals[:, 0, 0])
|
||||
start = max(signals[:, 0, 0])
|
||||
end = min(signals[:, 0, -1])
|
||||
|
||||
splines = [
|
||||
CubicSpline(signal[0], signal[1]) for signal in signals
|
||||
]
|
||||
|
||||
x = arange(start, end, 1 / max(rates))
|
||||
|
||||
signals = [array([x, spline(x)]) for spline in splines]
|
||||
|
||||
return signals
|
||||
|
||||
def compute_light(self):
|
||||
"""
|
||||
Compute psd of the computed projection with current bench
|
||||
excitation
|
||||
"""
|
||||
coupling = self.modelisation[self.settings.coupling_name()]
|
||||
|
||||
coupling_1, coupling_2 = (
|
||||
array(
|
||||
[
|
||||
self.modelisation["freq"][0],
|
||||
coupling[0],
|
||||
]
|
||||
),
|
||||
array(
|
||||
[
|
||||
self.modelisation["freq"][0],
|
||||
coupling[1],
|
||||
]
|
||||
),
|
||||
)
|
||||
|
||||
rate = 1 / (self.movement[0, 1] - self.movement[0, 0])
|
||||
|
||||
result = zeros(self.bench_movement.shape[1])
|
||||
scattering_factor = [0, 0]
|
||||
|
||||
for index in range(
|
||||
len(self.modelisation[self.settings.coupling_name()])
|
||||
):
|
||||
argument = (
|
||||
self.movement[1]
|
||||
* 4
|
||||
* pi
|
||||
* (index + 1)
|
||||
/ self.settings.wavelength
|
||||
)
|
||||
|
||||
result += (
|
||||
scattering_factor[index]
|
||||
* (self.settings.wavelength / 4 * pi) ** 2
|
||||
* (
|
||||
(
|
||||
psd(
|
||||
sin(argument),
|
||||
fs=rate,
|
||||
nperseg=2999,
|
||||
)[1]
|
||||
* abs(coupling[0])
|
||||
)
|
||||
** 2
|
||||
+ (
|
||||
psd(
|
||||
cos(argument),
|
||||
fs=rate,
|
||||
nperseg=2999,
|
||||
)[1]
|
||||
* abs(coupling[1])
|
||||
)
|
||||
** 2
|
||||
)
|
||||
)
|
||||
return result
|
146
src/backscattering-analyzer/settings.py
Normal file
146
src/backscattering-analyzer/settings.py
Normal file
|
@ -0,0 +1,146 @@
|
|||
from pathlib import Path
|
||||
|
||||
|
||||
class Settings:
|
||||
def __init__(self, options, console):
|
||||
self.version = "0.0.1"
|
||||
self.help = (
|
||||
"[main]display[/main] [option]\\[options][/option]"
|
||||
"\n [argument]-b --bench[argument] [description]bench of the experiment[/description]"
|
||||
"\n [argument]-d --date[argument] [description]date of the experiment[/description]"
|
||||
"\n [argument]-h --help[argument] [description]print this help and exit[/description]"
|
||||
"\n [argument]-v --verbose[argument] [description]be verbose[/description]"
|
||||
"\n [argument]-V --version[argument] [description]print version number and exit[/description]"
|
||||
)
|
||||
self.verbose = False
|
||||
self.bench = "SWEB"
|
||||
self.date = "2023_03_24"
|
||||
self.folder = Path("/home/demagny/data")
|
||||
self.modelisation = "scatterCouplingO4.mat"
|
||||
self.wavelength = 1.064e-6
|
||||
|
||||
index = 0
|
||||
while index < len(options):
|
||||
option = options[index]
|
||||
try:
|
||||
if option[0] != "-":
|
||||
if option == "h":
|
||||
option = "--help"
|
||||
if option == "V":
|
||||
option = "--version"
|
||||
if "v" in option:
|
||||
options[index] = option.replace("v", "")
|
||||
option = "--verbose"
|
||||
index -= 1
|
||||
if option == "b":
|
||||
index += 1
|
||||
try:
|
||||
options[index] = "--bench={}".format(
|
||||
options[index]
|
||||
)
|
||||
except IndexError:
|
||||
raise Exception(
|
||||
"bench name needed after b option"
|
||||
)
|
||||
if option == "d":
|
||||
index += 1
|
||||
try:
|
||||
options[index] = "--date={}".format(
|
||||
options[index]
|
||||
)
|
||||
except IndexError:
|
||||
raise Exception(
|
||||
"date needed after d option"
|
||||
)
|
||||
if option[0] == "-":
|
||||
if option[1] != "-":
|
||||
if option == "-h":
|
||||
option = "--help"
|
||||
if option == "-V":
|
||||
option = "--version"
|
||||
if "v" in option:
|
||||
options[index] = option.replace("v", "")
|
||||
option = "--verbose"
|
||||
index -= 1
|
||||
if option == "-b":
|
||||
index += 1
|
||||
try:
|
||||
options[index] = "--bench={}".format(
|
||||
options[index]
|
||||
)
|
||||
except IndexError:
|
||||
raise Exception(
|
||||
"bench name needed after -b option"
|
||||
)
|
||||
if option == "-d":
|
||||
index += 1
|
||||
try:
|
||||
options[index] = "--date={}".format(
|
||||
options[index]
|
||||
)
|
||||
except IndexError:
|
||||
raise Exception(
|
||||
"date needed after -d option"
|
||||
)
|
||||
if option[:2] == "--":
|
||||
if option == "--help":
|
||||
console.print(self.help)
|
||||
exit(0)
|
||||
if option == "--version":
|
||||
console.print(self.version)
|
||||
exit(0)
|
||||
if option == "--verbose":
|
||||
self.verbose = True
|
||||
try:
|
||||
if option[:8] == "--bench=":
|
||||
self.bench = str(option[8:]).upper()
|
||||
except IndexError:
|
||||
continue
|
||||
try:
|
||||
if option[:7] == "--date=":
|
||||
self.date = option[7:]
|
||||
except IndexError:
|
||||
continue
|
||||
else:
|
||||
raise Exception("unknown option {}".format(option))
|
||||
except IndexError:
|
||||
pass
|
||||
index += 1
|
||||
|
||||
def bench_file(self):
|
||||
return self.folder / (
|
||||
"{bench}_{date}_ben.csv".format(
|
||||
bench=self.bench,
|
||||
date=self.date,
|
||||
)
|
||||
)
|
||||
|
||||
def mirror_file(self):
|
||||
return self.folder / (
|
||||
"{bench}_{date}_mir.csv".format(
|
||||
bench=self.bench,
|
||||
date=self.date,
|
||||
)
|
||||
)
|
||||
|
||||
def data_file(self):
|
||||
return self.folder / (
|
||||
"{bench}_{date}_dat.csv".format(
|
||||
bench=self.bench,
|
||||
date=self.date,
|
||||
)
|
||||
)
|
||||
|
||||
def reference_file(self):
|
||||
return self.folder / (
|
||||
"{bench}_{date}_ref.csv".format(
|
||||
bench=self.bench,
|
||||
date=self.date,
|
||||
)
|
||||
)
|
||||
|
||||
def modelisation_file(self):
|
||||
return self.folder / (self.modelisation)
|
||||
|
||||
def coupling_name(self):
|
||||
return "{bench}coupling".format(bench=self.bench)
|
Loading…
Reference in a new issue