-
Notifications
You must be signed in to change notification settings - Fork 3
Add pseudo-orbit BPM reading mode #28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -172,6 +172,19 @@ def capture_injection(self, n_turns=1, bba=True, subtract_reference=True, use_de | |
| else: | ||
| return fake_trajectory_x_tbt, fake_trajectory_y_tbt | ||
|
|
||
| def capture_pseudo_orbit(self, n_turns=1, bba=True, subtract_reference=True, | ||
| use_design=False, return_transmission=False): | ||
| result = self.capture_injection( | ||
| n_turns=n_turns, bba=bba, subtract_reference=subtract_reference, | ||
| use_design=use_design, return_transmission=return_transmission | ||
| ) | ||
| if return_transmission: | ||
| x, y, transmission = result | ||
| return np.nanmean(x, axis=1), np.nanmean(y, axis=1), transmission | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer to catch np.nanmean warnings. They can get quite annoying. |
||
| else: | ||
| x, y = result | ||
| return np.nanmean(x, axis=1), np.nanmean(y, axis=1) | ||
|
|
||
| def capture_kick(self, n_turns=1, kick_px=0, kick_py=0, bba=True, subtract_reference=True, use_design=False) -> tuple[np.ndarray, np.ndarray]: | ||
| ''' | ||
| Simulates an orbit reading, after kicking a stored beam, from the BPMs, applying calibration errors, offsets/rolls, and noise. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -63,3 +63,13 @@ def get_ref_orbit(self) -> tuple[np.ndarray, np.ndarray]: | |
| x_ref = np.repeat(self.SC.bpm_system.reference_x[:, np.newaxis], self.n_turns, axis=1) | ||
| y_ref = np.repeat(self.SC.bpm_system.reference_y[:, np.newaxis], self.n_turns, axis=1) | ||
| return x_ref.flatten(order='F'), y_ref.flatten(order='F') | ||
|
|
||
| class pySCPseudoOrbitInterface(pySCOrbitInterface): | ||
| SC: "SimulatedCommissioning" = Field(repr=False) | ||
| n_turns: int = 1 | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. starting_turn=1 from above should be an attribute of the class here |
||
|
|
||
| def get_orbit(self) -> tuple[np.ndarray, np.ndarray]: | ||
| return self.SC.bpm_system.capture_pseudo_orbit( | ||
| n_turns=self.n_turns, use_design=self.use_design, | ||
| bba=self.bba, subtract_reference=self.subtract_reference | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,7 @@ | |
| from .c_minus import CMinus | ||
| from .rf_tuning import RF_tuning | ||
| from ..core.control import IndivControl | ||
| from .pySC_interface import pySCInjectionInterface, pySCOrbitInterface | ||
| from .pySC_interface import pySCInjectionInterface, pySCOrbitInterface, pySCPseudoOrbitInterface | ||
| from ..apps import orbit_correction | ||
|
|
||
| import numpy as np | ||
|
|
@@ -186,61 +186,41 @@ def correct_injection(self, n_turns=1, n_reps=1, method='tikhonov', parameter=10 | |
|
|
||
| return | ||
|
|
||
| def correct_orbit(self, n_reps=1, method='tikhonov', parameter=100, gain=1, virtual=False): | ||
| def correct_orbit(self, n_reps=1, method='tikhonov', parameter=100, gain=1, virtual=False, | ||
| pseudo=False, n_turns=1): | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should raise an error/warning if n_turns and starting_turn is redefined but pseudo is False |
||
| RM_name = 'orbit' | ||
| self.fetch_response_matrix(RM_name, orbit=True) | ||
| response_matrix = self.response_matrix[RM_name] | ||
| response_matrix.bad_outputs = self.bad_outputs_from_bad_bpms(self.bad_bpms) | ||
|
|
||
| SC = self._parent | ||
| interface = pySCOrbitInterface(SC=SC) | ||
| if pseudo: | ||
| interface = pySCPseudoOrbitInterface(SC=SC, n_turns=n_turns) | ||
| else: | ||
| interface = pySCOrbitInterface(SC=SC) | ||
|
|
||
| for _ in range(n_reps): | ||
| _ = orbit_correction(interface=interface, response_matrix=response_matrix, reference=None, | ||
| method=method, parameter=parameter, virtual=virtual, gain=gain, apply=True) | ||
|
|
||
| orbit_x, orbit_y = SC.bpm_system.capture_orbit() | ||
| rms_x = np.nanstd(orbit_x) * 1e6 | ||
| rms_y = np.nanstd(orbit_y) * 1e6 | ||
| logger.info(f'Corrected orbit: {rms_x=:.1f} um, {rms_y=:.1f} um.') | ||
| if pseudo: | ||
| orbit_x, orbit_y = SC.bpm_system.capture_pseudo_orbit(n_turns=n_turns) | ||
| rms_x = np.nanstd(orbit_x) * 1e6 | ||
| rms_y = np.nanstd(orbit_y) * 1e6 | ||
| logger.info(f'Corrected pseudo-orbit ({n_turns} turns): {rms_x=:.1f} um, {rms_y=:.1f} um.') | ||
| else: | ||
| orbit_x, orbit_y = SC.bpm_system.capture_orbit() | ||
| rms_x = np.nanstd(orbit_x) * 1e6 | ||
| rms_y = np.nanstd(orbit_y) * 1e6 | ||
| logger.info(f'Corrected orbit: {rms_x=:.1f} um, {rms_y=:.1f} um.') | ||
| return | ||
|
|
||
| # def correct_pseudo_orbit_at_injection(self, n_turns=1, n_reps=1, method='tikhonov', parameter=100, gain=1, zerosum=False): | ||
| # RM_name = 'orbit' | ||
| # self.fetch_response_matrix(RM_name, orbit=True) | ||
| # RM = self.response_matrix[RM_name] | ||
| # RM.bad_outputs = self.bad_outputs_from_bad_bpms(self.bad_bpms) | ||
|
|
||
| # for _ in range(n_reps): | ||
| # trajectory_x, trajectory_y = self._parent.bpm_system.capture_injection(n_turns=n_turns) | ||
| # pseudo_orbit_x = np.nanmean(trajectory_x, axis=1) | ||
| # pseudo_orbit_y = np.nanmean(trajectory_y, axis=1) | ||
| # pseudo_orbit = np.concat((pseudo_orbit_x, pseudo_orbit_y)) | ||
|
|
||
| # trims = RM.solve(pseudo_orbit, method=method, parameter=parameter, zerosum=zerosum) | ||
|
|
||
| # settings = self._parent.magnet_settings | ||
| # for control_name, trim in zip(self.CORR, trims): | ||
| # setpoint = settings.get(control_name=control_name) - gain * trim | ||
| # settings.set(control_name=control_name, setpoint=setpoint) | ||
|
|
||
| # trajectory_x, trajectory_y = self._parent.bpm_system.capture_injection(n_turns=n_turns) | ||
| # trajectory_x = trajectory_x.flatten('F') | ||
| # trajectory_y = trajectory_y.flatten('F') | ||
| # rms_x = np.nanstd(trajectory_x) * 1e6 | ||
| # rms_y = np.nanstd(trajectory_y) * 1e6 | ||
| # bad_readings = sum(np.isnan(trajectory_x)) | ||
| # good_turns = (len(trajectory_x) - bad_readings) / len(self._parent.bpm_system.indices) | ||
| # logger.info(f'Corrected injection: transmission through {good_turns:.2f}/{n_turns} turns, {rms_x=:.1f} um, {rms_y=:.1f} um.') | ||
|
|
||
| # return | ||
|
|
||
| def fit_dispersive_orbit(self): | ||
| SC = self._parent | ||
| response = measure_RFFrequencyOrbitResponse(SC=SC, use_design=True) | ||
|
|
||
| x,y = SC.bpm_system.capture_orbit(bba=False, subtract_reference=False, use_design=False) | ||
| xy = np.concat((x.flatten(order='F'), y.flatten(order='F'))) | ||
| xy = np.concatenate((x.flatten(order='F'), y.flatten(order='F'))) | ||
|
|
||
| return np.dot(xy, response) / np.dot(response, response) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to have a "starting_turn=1" option in case one wants to define the pseudo-orbit from later turns for reasons like fast-kicker orbit bumps, decoherence, e.t.c