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]