sqil-core 0.1.0__py3-none-any.whl → 1.1.0__py3-none-any.whl
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.
- sqil_core/__init__.py +1 -0
- sqil_core/config_log.py +42 -0
- sqil_core/experiment/__init__.py +11 -0
- sqil_core/experiment/_analysis.py +125 -0
- sqil_core/experiment/_events.py +25 -0
- sqil_core/experiment/_experiment.py +553 -0
- sqil_core/experiment/data/plottr.py +778 -0
- sqil_core/experiment/helpers/_function_override_handler.py +111 -0
- sqil_core/experiment/helpers/_labone_wrappers.py +12 -0
- sqil_core/experiment/instruments/__init__.py +2 -0
- sqil_core/experiment/instruments/_instrument.py +190 -0
- sqil_core/experiment/instruments/drivers/SignalCore_SC5511A.py +515 -0
- sqil_core/experiment/instruments/local_oscillator.py +205 -0
- sqil_core/experiment/instruments/server.py +175 -0
- sqil_core/experiment/instruments/setup.yaml +21 -0
- sqil_core/experiment/instruments/zurich_instruments.py +55 -0
- sqil_core/fit/__init__.py +23 -0
- sqil_core/fit/_core.py +179 -31
- sqil_core/fit/_fit.py +544 -94
- sqil_core/fit/_guess.py +304 -0
- sqil_core/fit/_models.py +50 -1
- sqil_core/fit/_quality.py +266 -0
- sqil_core/resonator/__init__.py +2 -0
- sqil_core/resonator/_resonator.py +256 -74
- sqil_core/utils/__init__.py +40 -13
- sqil_core/utils/_analysis.py +226 -0
- sqil_core/utils/_const.py +83 -18
- sqil_core/utils/_formatter.py +127 -55
- sqil_core/utils/_plot.py +272 -6
- sqil_core/utils/_read.py +178 -95
- sqil_core/utils/_utils.py +147 -0
- {sqil_core-0.1.0.dist-info → sqil_core-1.1.0.dist-info}/METADATA +9 -1
- sqil_core-1.1.0.dist-info/RECORD +36 -0
- {sqil_core-0.1.0.dist-info → sqil_core-1.1.0.dist-info}/WHEEL +1 -1
- sqil_core-0.1.0.dist-info/RECORD +0 -19
- {sqil_core-0.1.0.dist-info → sqil_core-1.1.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,205 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
|
3
|
+
import yaml
|
4
|
+
from qcodes.instrument_drivers.rohde_schwarz import RohdeSchwarzSGS100A
|
5
|
+
from qcodes_contrib_drivers.drivers.SignalCore.SignalCore import SC5521A
|
6
|
+
|
7
|
+
from sqil_core.config_log import logger
|
8
|
+
from sqil_core.experiment.instruments import Instrument
|
9
|
+
from sqil_core.utils._formatter import format_number
|
10
|
+
|
11
|
+
from .drivers.SignalCore_SC5511A import SignalCore_SC5511A
|
12
|
+
|
13
|
+
|
14
|
+
class LocalOscillatorBase(Instrument, ABC):
|
15
|
+
def __init__(self, *args, **kwargs):
|
16
|
+
super().__init__(*args, **kwargs)
|
17
|
+
|
18
|
+
@abstractmethod
|
19
|
+
def set_frequency(self, value) -> None:
|
20
|
+
"""Set the frequency of the local oscillator."""
|
21
|
+
pass
|
22
|
+
|
23
|
+
@abstractmethod
|
24
|
+
def set_power(self, value) -> None:
|
25
|
+
"""Set the power of the local oscillator."""
|
26
|
+
pass
|
27
|
+
|
28
|
+
@abstractmethod
|
29
|
+
def turn_on(self) -> None:
|
30
|
+
"""Turn the local oscillator on."""
|
31
|
+
pass
|
32
|
+
|
33
|
+
@abstractmethod
|
34
|
+
def turn_off(self) -> None:
|
35
|
+
"""Turn the local oscillator off."""
|
36
|
+
pass
|
37
|
+
|
38
|
+
|
39
|
+
class SqilRohdeSchwarzSGS100A(LocalOscillatorBase):
|
40
|
+
"""
|
41
|
+
Frequency:
|
42
|
+
[1 MHz, 20 GHz], resolution 0.001 Hz
|
43
|
+
Power:
|
44
|
+
[-120 dB, 25 dB], resolution 0.01 dB
|
45
|
+
"""
|
46
|
+
|
47
|
+
def _default_connect(self, *args, **kwargs):
|
48
|
+
logger.info(f"Connecting to {self.name} ({self.model})")
|
49
|
+
return RohdeSchwarzSGS100A(self.name, self.address)
|
50
|
+
|
51
|
+
def _default_disconnect(self, *args, **kwargs):
|
52
|
+
logger.info(f"Disconnecting from {self.name} ({self.model})")
|
53
|
+
self.turn_off()
|
54
|
+
|
55
|
+
def _default_setup(self, *args, **kwargs):
|
56
|
+
logger.info(f"Setting up {self.name}")
|
57
|
+
self.turn_off()
|
58
|
+
self.set_power(-60)
|
59
|
+
|
60
|
+
def set_frequency(self, value) -> None:
|
61
|
+
self.device.frequency(value)
|
62
|
+
|
63
|
+
def set_power(self, value) -> None:
|
64
|
+
self.device.power(value)
|
65
|
+
|
66
|
+
def turn_on(self) -> None:
|
67
|
+
self.device.on()
|
68
|
+
|
69
|
+
def turn_off(self) -> None:
|
70
|
+
self.device.off()
|
71
|
+
|
72
|
+
|
73
|
+
class SqilSignalCoreSC5511A(LocalOscillatorBase):
|
74
|
+
"""
|
75
|
+
PORT 1 specifications
|
76
|
+
Frequency:
|
77
|
+
[100 MHz, 20 GHz], resolution 1 Hz
|
78
|
+
Power:
|
79
|
+
@ freq < 18 GHz: [-20 dBm, 15 dBm], resolution 0.01 dBm
|
80
|
+
@ freq > 18 GHz: [-20 dBm, 10 dBm], resolution 0.01 dBm
|
81
|
+
"""
|
82
|
+
|
83
|
+
def _default_connect(self, *args, **kwargs):
|
84
|
+
logger.info(f"Connecting to {self.name} ({self.model})")
|
85
|
+
return SignalCore_SC5511A(self.name, self.address)
|
86
|
+
|
87
|
+
def _default_disconnect(self, *args, **kwargs):
|
88
|
+
logger.info(f"Disconnecting from {self.name} ({self.model})")
|
89
|
+
self.turn_off()
|
90
|
+
|
91
|
+
def _default_setup(self, *args, **kwargs):
|
92
|
+
logger.info(f"Setting up {self.name}")
|
93
|
+
self.turn_off()
|
94
|
+
self.set_power(-40)
|
95
|
+
self.device.do_set_reference_source(1) # to enable phase locking
|
96
|
+
self.device.do_set_standby(True) # update PLL locking
|
97
|
+
self.device.do_set_standby(False)
|
98
|
+
|
99
|
+
def set_frequency(self, value) -> None:
|
100
|
+
self.device.do_set_ref_out_freq(value)
|
101
|
+
|
102
|
+
def set_power(self, value) -> None:
|
103
|
+
self.device.power(value)
|
104
|
+
|
105
|
+
def turn_on(self) -> None:
|
106
|
+
self.device.do_set_output_status(1)
|
107
|
+
|
108
|
+
def turn_off(self) -> None:
|
109
|
+
self.device.do_set_output_status(0)
|
110
|
+
|
111
|
+
|
112
|
+
class SqilSignalCoreSC5521A(LocalOscillatorBase):
|
113
|
+
"""
|
114
|
+
Frequency:
|
115
|
+
[160 MHz, 40 GHz], resolution 1 Hz
|
116
|
+
Power:
|
117
|
+
@ freq < 30 GHz: [-10 dBm, 15 dBm], resolution 0.1 dBm
|
118
|
+
@ freq < 35 GHz: [-10 dBm, 10 dBm], resolution 0.1 dBm
|
119
|
+
@ freq > 35 GHz: [-10 dBm, 3 dBm], resolution 0.1 dBm
|
120
|
+
"""
|
121
|
+
|
122
|
+
def _default_connect(self, *args, **kwargs):
|
123
|
+
logger.info(f"Connecting to {self.name} ({self.model})")
|
124
|
+
return SC5521A(self.name)
|
125
|
+
|
126
|
+
def _default_disconnect(self, *args, **kwargs):
|
127
|
+
logger.info(f"Disconnecting from {self.name} ({self.model})")
|
128
|
+
self.turn_off()
|
129
|
+
|
130
|
+
def _default_setup(self, *args, **kwargs):
|
131
|
+
logger.info(f"Setting up {self.name}")
|
132
|
+
self.turn_off()
|
133
|
+
self.set_power(-40)
|
134
|
+
|
135
|
+
def set_frequency(self, value) -> None:
|
136
|
+
self.device.clock_frequency(value)
|
137
|
+
|
138
|
+
def set_power(self, value) -> None:
|
139
|
+
self.device.power(value)
|
140
|
+
|
141
|
+
def turn_on(self) -> None:
|
142
|
+
self.device.status("on")
|
143
|
+
|
144
|
+
def turn_off(self) -> None:
|
145
|
+
self.device.status("off")
|
146
|
+
|
147
|
+
|
148
|
+
class LocalOscillator(LocalOscillatorBase):
|
149
|
+
def __init__(self, *args, **kwargs):
|
150
|
+
super().__init__(*args, **kwargs)
|
151
|
+
|
152
|
+
model = kwargs.get("config", {}).get("model", "")
|
153
|
+
if model == "RohdeSchwarzSGS100A":
|
154
|
+
self._device_class = SqilRohdeSchwarzSGS100A
|
155
|
+
elif model == "SignalCore_SC5511A":
|
156
|
+
self._device_class = SqilSignalCoreSC5511A
|
157
|
+
elif model == "SC5521A":
|
158
|
+
self._device_class = SqilSignalCoreSC5521A
|
159
|
+
else:
|
160
|
+
raise ValueError(f"Unsupported model: {model}")
|
161
|
+
|
162
|
+
self.instrument = self._device_class(self.id, self.config)
|
163
|
+
|
164
|
+
def _default_connect(self, *args, **kwargs):
|
165
|
+
pass
|
166
|
+
|
167
|
+
def _default_disconnect(self, *args, **kwargs):
|
168
|
+
pass
|
169
|
+
|
170
|
+
def _default_setup(self, *args, **kwargs):
|
171
|
+
pass
|
172
|
+
|
173
|
+
def _default_on_before_experiment(self, *args, sender=None, **kwargs):
|
174
|
+
self.turn_on()
|
175
|
+
|
176
|
+
def _default_on_before_sequence(self, *args, sender=None, **kwargs):
|
177
|
+
freq = self.get_variable("frequency", sender)
|
178
|
+
power = self.get_variable("power", sender)
|
179
|
+
if freq:
|
180
|
+
self.set_frequency(freq)
|
181
|
+
if power:
|
182
|
+
self.set_power(power)
|
183
|
+
|
184
|
+
def _default_on_after_experiment(self, *args, sender=None, **kwargs):
|
185
|
+
self.turn_off()
|
186
|
+
|
187
|
+
def set_frequency(self, value) -> None:
|
188
|
+
logger.info(
|
189
|
+
f"Setting frequency to {format_number(value, 5, unit="Hz", latex=False)} for {self.name}"
|
190
|
+
)
|
191
|
+
self.instrument.set_frequency(value)
|
192
|
+
|
193
|
+
def set_power(self, value) -> None:
|
194
|
+
logger.info(
|
195
|
+
f"Setting power to {format_number(value, 4, unit="dB", latex=False)} for {self.name}"
|
196
|
+
)
|
197
|
+
self.instrument.set_power(value)
|
198
|
+
|
199
|
+
def turn_on(self) -> None:
|
200
|
+
logger.info(f"Turning on {self.name}")
|
201
|
+
self.instrument.turn_on()
|
202
|
+
|
203
|
+
def turn_off(self) -> None:
|
204
|
+
logger.info(f"Turning off {self.name}")
|
205
|
+
self.instrument.turn_off()
|
@@ -0,0 +1,175 @@
|
|
1
|
+
import os
|
2
|
+
import pickle
|
3
|
+
import sys
|
4
|
+
from typing import cast
|
5
|
+
|
6
|
+
import Pyro5.api as pyro
|
7
|
+
import Pyro5.errors as pyro_errors
|
8
|
+
|
9
|
+
from sqil_core.config_log import logger
|
10
|
+
from sqil_core.experiment.instruments import Instrument
|
11
|
+
from sqil_core.experiment.instruments.local_oscillator import LocalOscillator
|
12
|
+
from sqil_core.experiment.instruments.zurich_instruments import ZI_Instrument
|
13
|
+
from sqil_core.utils._read import read_yaml
|
14
|
+
from sqil_core.utils._utils import _extract_variables_from_module, _hash_file
|
15
|
+
|
16
|
+
_instrument_classes = {
|
17
|
+
"LO": LocalOscillator,
|
18
|
+
"ZI": ZI_Instrument,
|
19
|
+
}
|
20
|
+
|
21
|
+
|
22
|
+
@pyro.expose
|
23
|
+
class InstrumentServer:
|
24
|
+
"""
|
25
|
+
Instruments server. Configures the instruments once and distributes instrument instances to other modules.
|
26
|
+
Providing the path of the setup file is not required, but it allows to detect changes in the setup file that
|
27
|
+
require the server to restart.
|
28
|
+
The server is available at PYRO:SERVER@localhost:9090.
|
29
|
+
"""
|
30
|
+
|
31
|
+
NAME = "SERVER"
|
32
|
+
PORT = 9090
|
33
|
+
URI = f"PYRO:{NAME}@localhost:{PORT}"
|
34
|
+
|
35
|
+
def __init__(self, instrument_dict: dict, setup_path="") -> None:
|
36
|
+
logger.info("Starting server")
|
37
|
+
self._instruments = connect_instruments(instrument_dict)
|
38
|
+
self._daemon = pyro.Daemon(port=InstrumentServer.PORT)
|
39
|
+
self._services: dict[str, pyro.URI] = {}
|
40
|
+
|
41
|
+
self._setup_path = os.path.abspath(setup_path)
|
42
|
+
self._setup_hash = None
|
43
|
+
if setup_path:
|
44
|
+
self._setup_hash = _hash_file(self._setup_path)
|
45
|
+
logger.info(f"Setup path: {self._setup_path}")
|
46
|
+
logger.info(f"Setup hash: {str(self.setup_hash)}")
|
47
|
+
|
48
|
+
def serve(self) -> None:
|
49
|
+
self._expose()
|
50
|
+
for id, instrument in self._instruments.items():
|
51
|
+
uri = self._daemon.register(instrument, objectId=instrument.id)
|
52
|
+
self._services[id] = uri
|
53
|
+
logger.info(f"Registered {instrument = } with daemon at {uri = }.")
|
54
|
+
self._daemon.register(self, objectId=InstrumentServer.NAME)
|
55
|
+
with self._daemon:
|
56
|
+
logger.info("Local server setup complete! Now listening for requests...")
|
57
|
+
self._daemon.requestLoop()
|
58
|
+
|
59
|
+
def _expose(self) -> None:
|
60
|
+
classes = {instrument.__class__ for _, instrument in self._instruments.items()}
|
61
|
+
# classes |= {Session}
|
62
|
+
for cls in classes:
|
63
|
+
pyro.expose(cls)
|
64
|
+
logger.info(f"Exposed class {cls} to Pyro5.")
|
65
|
+
|
66
|
+
def shutdown(self) -> None:
|
67
|
+
logger.info("Shutting down the local server...")
|
68
|
+
self._disconnect_all()
|
69
|
+
with self._daemon:
|
70
|
+
self._daemon.shutdown()
|
71
|
+
logger.info("Local server shutdown complete!")
|
72
|
+
|
73
|
+
def _disconnect_all(self) -> None:
|
74
|
+
logger.info("Disonnecting instruments...")
|
75
|
+
for _, instrument in self._instruments.items():
|
76
|
+
instrument.disconnect()
|
77
|
+
|
78
|
+
@property
|
79
|
+
def services(self) -> dict[str, pyro.URI]:
|
80
|
+
return {**self._services}
|
81
|
+
|
82
|
+
@property
|
83
|
+
def setup_hash(self) -> str | None:
|
84
|
+
return self._setup_hash
|
85
|
+
|
86
|
+
@property
|
87
|
+
def setup_path(self) -> str:
|
88
|
+
return self._setup_path
|
89
|
+
|
90
|
+
|
91
|
+
def link_instrument_server() -> tuple[pyro.Proxy, dict[str, pyro.Proxy]]:
|
92
|
+
"""Link to the instruments server."""
|
93
|
+
server = pyro.Proxy(InstrumentServer.URI)
|
94
|
+
|
95
|
+
if server.setup_path:
|
96
|
+
current_hash = _hash_file(server.setup_path)
|
97
|
+
print(server.setup_hash, current_hash)
|
98
|
+
if current_hash != server.setup_hash:
|
99
|
+
message = (
|
100
|
+
f"Changes detected in the setup file {server.setup_path}. "
|
101
|
+
+ "Please restart the server to apply the changes."
|
102
|
+
)
|
103
|
+
logger.error(message)
|
104
|
+
raise Exception(message)
|
105
|
+
|
106
|
+
try:
|
107
|
+
services = cast(dict[str, pyro.URI], server.services)
|
108
|
+
except pyro_errors.CommunicationError as err:
|
109
|
+
logger.error(f"Local server not found at {InstrumentServer.URI}")
|
110
|
+
raise err from None
|
111
|
+
else:
|
112
|
+
instruments = {id: pyro.Proxy(uri) for id, uri in services.items()}
|
113
|
+
return (server, instruments)
|
114
|
+
|
115
|
+
|
116
|
+
def unlink_instrument_server(server: pyro.Proxy, **instruments: pyro.Proxy) -> None:
|
117
|
+
"""Unlink from the instruments server."""
|
118
|
+
server._pyroRelease()
|
119
|
+
for _, instrument in instruments.items():
|
120
|
+
instrument._pyroRelease()
|
121
|
+
|
122
|
+
|
123
|
+
def start_instrument_server(setup_path: str = ""):
|
124
|
+
"""Start a new instruments server using the provided setup file.
|
125
|
+
If the path to the setup file is not provided it will be guessedby readig ./config.yaml.
|
126
|
+
"""
|
127
|
+
if not setup_path:
|
128
|
+
config = read_yaml("config.yaml")
|
129
|
+
setup_path = config.get("setup_path", "setup.py")
|
130
|
+
setup = _extract_variables_from_module("setup", setup_path)
|
131
|
+
|
132
|
+
instrument_dict = setup.get("instruments", None)
|
133
|
+
if not instrument_dict:
|
134
|
+
logger.warning(
|
135
|
+
f"Unable to find any instruments in {setup_path}"
|
136
|
+
+ "Do you have an `instruments` entry in your setup file?"
|
137
|
+
)
|
138
|
+
return None
|
139
|
+
|
140
|
+
server = InstrumentServer(instrument_dict, setup_path=setup_path)
|
141
|
+
server.serve()
|
142
|
+
|
143
|
+
return server
|
144
|
+
|
145
|
+
|
146
|
+
def connect_instruments(
|
147
|
+
instrument_dict: dict | None,
|
148
|
+
) -> dict[str, Instrument]:
|
149
|
+
if not instrument_dict:
|
150
|
+
return {}
|
151
|
+
|
152
|
+
instance_dict = {}
|
153
|
+
for instrument_id, config in instrument_dict.items():
|
154
|
+
instrument_type = config.get("type")
|
155
|
+
instrument_factory = _instrument_classes.get(instrument_type)
|
156
|
+
|
157
|
+
if not instrument_factory:
|
158
|
+
logger.warning(
|
159
|
+
f"Unknown instrument type '{instrument_type}' for '{instrument_id}'. "
|
160
|
+
f"Available types: {list(_instrument_classes.keys())}"
|
161
|
+
)
|
162
|
+
continue
|
163
|
+
|
164
|
+
try:
|
165
|
+
instance = instrument_factory(instrument_id, config=config)
|
166
|
+
instance_dict[instrument_id] = instance
|
167
|
+
logger.info(
|
168
|
+
f"Successfully connected to {config.get('name', instrument_id)}"
|
169
|
+
)
|
170
|
+
except Exception as e:
|
171
|
+
logger.error(
|
172
|
+
f"Failed to connect to {config.get('name', instrument_id)}: {str(e)}"
|
173
|
+
)
|
174
|
+
sys.exit(-1)
|
175
|
+
return instance_dict
|
@@ -0,0 +1,21 @@
|
|
1
|
+
param_dict_path: >
|
2
|
+
./param_dict.py
|
3
|
+
|
4
|
+
instruments:
|
5
|
+
sgsa:
|
6
|
+
name: "SGSA100"
|
7
|
+
address: "TCPIP0::128.178.120.72::inst0::INSTR"
|
8
|
+
model: "RohdeSchwarzSGS100A"
|
9
|
+
type: "LO"
|
10
|
+
|
11
|
+
SC5511A:
|
12
|
+
name: "SC"
|
13
|
+
address: "10003C68"
|
14
|
+
model: "SignalCore_SC5511A"
|
15
|
+
type: "LO"
|
16
|
+
|
17
|
+
SC5521A:
|
18
|
+
name: "mw1"
|
19
|
+
address: "" #name based connection, don't need address
|
20
|
+
model: "SC5521A"
|
21
|
+
type: "LO"
|
@@ -0,0 +1,55 @@
|
|
1
|
+
from laboneq.dsl.quantum import QPU
|
2
|
+
from laboneq.simple import DeviceSetup, Session
|
3
|
+
|
4
|
+
from sqil_core.experiment.instruments import Instrument
|
5
|
+
|
6
|
+
|
7
|
+
class ZI_Instrument(Instrument):
|
8
|
+
_descriptor = ""
|
9
|
+
_generate_setup = None
|
10
|
+
_generate_qpu = None
|
11
|
+
|
12
|
+
def __init__(self, id, config):
|
13
|
+
super().__init__(id, config)
|
14
|
+
self._descriptor = config.get("descriptor", "")
|
15
|
+
|
16
|
+
self._generate_setup = config.get("generate_setup", None)
|
17
|
+
if not self._generate_setup:
|
18
|
+
raise NotImplementedError(
|
19
|
+
"get_setup is not implemented in your setup file.\n"
|
20
|
+
+ "You should define it as part of the zi section of your instruments dictionary.\n"
|
21
|
+
+ "instruments['zi']['generate_setup']"
|
22
|
+
)
|
23
|
+
|
24
|
+
self._generate_qpu = config.get("generate_qpu", None)
|
25
|
+
if not self._generate_qpu:
|
26
|
+
raise NotImplementedError(
|
27
|
+
"get_qpu is not implemented in your setup file.\n"
|
28
|
+
+ "You should define it as part of the zi section of your instruments dictionary.\n"
|
29
|
+
+ "instruments['zi']['generate_qpu']"
|
30
|
+
)
|
31
|
+
|
32
|
+
def generate_setup(self, *params, **kwargs) -> DeviceSetup:
|
33
|
+
return self._generate_setup(*params, **kwargs)
|
34
|
+
|
35
|
+
def generate_qpu(self, *params, **kwargs) -> QPU:
|
36
|
+
return self._generate_qpu(*params, **kwargs)
|
37
|
+
|
38
|
+
def _default_connect(self):
|
39
|
+
pass
|
40
|
+
# setup = self.config.get("setup_obj", None)
|
41
|
+
# if setup is not None:
|
42
|
+
# self._session = Session(setup)
|
43
|
+
# return self.session
|
44
|
+
# raise "Zuirch instruments needs a 'setup_obj' field in your setup file"
|
45
|
+
|
46
|
+
def _default_setup(self):
|
47
|
+
pass
|
48
|
+
|
49
|
+
def _default_disconnect(self):
|
50
|
+
pass
|
51
|
+
|
52
|
+
@property
|
53
|
+
def descriptor(self):
|
54
|
+
"""LaboneQ descriptor (read-only) - deprecated."""
|
55
|
+
return self._descriptor
|
sqil_core/fit/__init__.py
CHANGED
@@ -11,6 +11,29 @@ from ._fit import (
|
|
11
11
|
fit_decaying_oscillations,
|
12
12
|
fit_gaussian,
|
13
13
|
fit_lorentzian,
|
14
|
+
fit_many_decaying_oscillations,
|
15
|
+
fit_oscillations,
|
14
16
|
fit_qubit_relaxation_qp,
|
15
17
|
fit_skewed_lorentzian,
|
18
|
+
fit_two_gaussians_shared_x0,
|
19
|
+
fit_two_lorentzians_shared_x0,
|
20
|
+
transform_data,
|
21
|
+
)
|
22
|
+
from ._guess import (
|
23
|
+
decaying_oscillations_bounds,
|
24
|
+
decaying_oscillations_guess,
|
25
|
+
estimate_peak,
|
26
|
+
gaussian_bounds,
|
27
|
+
gaussian_guess,
|
28
|
+
lorentzian_bounds,
|
29
|
+
lorentzian_guess,
|
30
|
+
oscillations_bounds,
|
31
|
+
oscillations_guess,
|
32
|
+
)
|
33
|
+
from ._quality import (
|
34
|
+
FIT_QUALITY_THRESHOLDS,
|
35
|
+
FitQuality,
|
36
|
+
evaluate_fit_quality,
|
37
|
+
get_best_fit,
|
38
|
+
get_best_fit_nrmse_aic,
|
16
39
|
)
|