backscattering_simulation/utils.py
2025-07-16 15:22:16 +02:00

105 lines
3.1 KiB
Python

from typing import Any
from finesse.model import Model, Port, SeriesSolution, DegreeOfFreedom
from finesse.components import SignalGenerator
from finesse.detectors import PowerDetectorDemod1
from finesse.analysis.actions.axes import Xaxis, Noxaxis
from numpy.typing import NDArray
from numpy import float64
def typingfix_seriessolution(
solution: None | SeriesSolution | tuple[Any],
) -> SeriesSolution:
if solution is None:
raise ValueError("Result of the simulation is None")
if isinstance(solution, tuple):
raise ValueError("Result is not in the expected format")
return solution
def fix_dark_fringe(model: Model, power: float) -> tuple[int, float]:
solution: SeriesSolution = typingfix_seriessolution(
model.run(Noxaxis())
)
if "B1_DC" not in solution.outputs:
raise Exception("Model does not contain B1 readout")
if type(model.get("DARM")) is DegreeOfFreedom:
result = solution["B1_DC"]
start, stop, nb = 0, 1, 0
while (abs(result - power) > 1e-6) and (nb < 500):
nb += 1
temp = start + (stop - start) / 2
model.get("DARM").DC = temp
solution: SeriesSolution = typingfix_seriessolution(
model.run(Noxaxis())
)
if "B1_DC" not in solution.outputs:
raise Exception("Model do not contains B1 readout")
result = solution["B1_DC"]
if result > power:
stop = temp
else:
start = temp
return nb, solution["B1_DC"]
raise Exception("DARM is not a degree of freedom in the model")
def compute_TF(
model: Model,
frequencies: NDArray[float64],
inputs: list[Port | str],
) -> SeriesSolution:
model.fsig.f = 1 # pyright: ignore[reportAttributeAccessIssue]
for input in inputs:
model.add(SignalGenerator("sig1", model.get(input), 1, 0))
model.add(
PowerDetectorDemod1(
"TF", model.get("SDB1").p2.o, f=model.get("fsig").f
)
)
model.get("TF").select_mask(exclude=(0, 0))
return model.run(
Xaxis(
model.fsig.f, # pyright: ignore[reportAttributeAccessIssue]
"log",
min(frequencies),
max(frequencies),
frequencies.shape[0] - 1,
)
)
class TF:
def __init__(
self,
model: Model,
inputs: list[Port | str],
outputs: list[Port | str],
frequencies: NDArray[float64],
):
self.model = model.deepcopy()
self.inputs = inputs
self.outputs = outputs
self.frequencies = frequencies
self.result: SeriesSolution | None = None
self.compute()
# alias
self.f = self.frequencies
def compute(self):
solution = compute_TF(self.model, self.frequencies, self.inputs)
self.result = solution
return self
def get(self, output: Port | str):
if self.result is None:
raise Exception(
"TF need to be computed before getting result"
)
return self.result[output]