WIP: quantum updates for more granular sub-budgets, mode mismatch, and RMS noises
Overhauled the quantum code to decompose the quantum noise into smaller elements. Useful more for comissioning budgets perhaps than design.
Also added some quantum noise degradations due to length RMS noises in filter cavity and SRC.
Finally, the quantum code now has mode mismatch. Still working on the interface to make it usable.
Merge request reports
Activity
added noise label
245 if np.iscomplexobj(total): 246 import warnings 247 warnings.warn("Trace {} is returning complex trace".format(self.name)) 241 248 242 249 return self._make_trace(psd=total) 243 250 251 def yield_trace(self, calibration=1, calc=True, _precomp=None): 252 """Calculate noise and return BudgetTrace object 253 254 `calibration` should either be a scalar or a len(self.freq) 255 array that will be multiplied to the output PSD of the budget 256 and all sub noises. 257 258 If `calc` is False, the noise will not be calculated and the 259 trace PSD will be None. This is useful for just getting the 260 trace style info. - gwinc/noise/quantum2.py 0 → 100644
375 QuantumRelASSqz, 376 QuantumRelASMisrotation, 377 ] 378 379 noises_forward = [ 380 (QuantumXi, QuantumXiAsqzCal), 381 (QuantumLoss, QuantumDisplacementInvCal), 382 ] 383 384 calibrations = [ 385 QuantumASPortInvCal, 386 ] 387 388 389 class QuantumRelGamma(nb.Budget): 390 """Quantum Vacuum 635 468 ] 636 469 637 470 471 ######################### 472 # quantum 473 ######################### 474 Quantum = quantum.Quantum 475 I don't think this definition is used anymore now that all of the
quantum2
functions are explicitly imported in the ifo init files. I'm in favor of just getting rid of the oldquantum
and replacing it withquantum2
. I am also a fan of the refactoring here where the precomps,nb.Noise
, andnb.Budget
definitions are moved toquantum2.py
(andsuspension.py
forprecomp_suspension
) and wonder if we should do this for the other noises in the future.I think the organization and grouping of these noises into sub-budgets in
quantum2.py
is pretty good and logical. However, there are a lot of sub-budgets and calibrations to follow. I think I understand them all now but it would be helpful for those not scrutinizing the code if the doc strings describe what the noise or calibration is along with the units.
11 color='#ad03de', 12 ) 13 14 noises = [ 15 QuantumVacuumAS, 16 QuantumVacuumArm, 17 QuantumVacuumSEC, 18 QuantumVacuumReadout, 19 ] 20 4 from gwinc.noise.quantum2 import ( 5 Quantum, 6 QuantumRelShotNoise, 7 QuantumRelGamma, 8 ) 21 9 mentioned in issue #94 (closed)
mentioned in commit 7dc75f96
mentioned in issue #96
mentioned in merge request !135 (merged)
- gwinc/noise/quantum2.py 0 → 100644
846 phaseARM = ilib.diag(np.exp(-pi2j * F_Hz * L_ARM_m / const.c)) @ ilib.Mrotation(-ARM_detune_rad, ARM_gouyRT_rad) 847 #arm round-trip as of the endmirror 848 rtARM = r_ETM @ phaseARM @ ilib.diag(rITM) @ phaseARM 849 reflArm = MM_ARM_SRC @ (ilib.diag(rITM) - (tITM * r_ETM @ phaseARM @ np.linalg.inv(ilib.Id - rtARM) @ phaseARM * tITM)) @ np.linalg.inv(MM_ARM_SRC) 850 transARM = MM_ARM_SRC @ (tITM * phaseARM) @ np.linalg.inv(ilib.Id - rtARM) 851 852 if SEC_lengthRMS_m != 0: 853 #I don't like that this requires a copy of the code, but can't do it without yet 854 ASshiftSEC = Hmats['AS'] 855 delta_SEC_L = 1e-13 856 phaseSRC = ilib.diag(np.exp(-pi2j * F_Hz * L_SRM_m / const.c)) @ ilib.Mrotation(-SRM_detune_rad + 2*np.pi * delta_SEC_L / lambda_, SRC_gouyRT_rad) 857 rtSRC = rSRM * (reflArm @ phaseSRC @ phaseSRC) * (1 - Loss_SRC)**0.5 858 reflAA_SECshift = MM_SQZ_OMC @ MM_SQZ_SRC @ mlib.promote(1, ilib.diag(rSRM) - (tSRM**2 * (1 - Loss_SRC)**0.5 * (phaseSRC @ ilib.Minv(ilib.Id - rtSRC) @ reflArm @ phaseSRC))) @ mlib.Minv(MM_SQZ_SRC) 859 ASshiftSEC = olib.promote(1, reflAA_SECshift) @ ASshiftSEC 860 861 phaseSRC = ilib.diag(np.exp(-pi2j * F_Hz * L_SRM_m / const.c)) @ ilib.Mrotation(-SRM_detune_rad, SRC_gouyRT_rad) It looks like
SRM_detune_rad
is the one-way SRC detuning which is specified byifo.Optics.SRM.Tunephase
in the yaml files. However,ifo.Optics.SRM.Tunephase
is the round-trip SRC detuning as currently used. See here.I personally prefer using the one-way detuning.
mentioned in issue #99
- gwinc/noise/quantum2.py 0 → 100644
712 dLOtheta_IFO = (Dptheta_IFO - theta_IFO) / delta_LO_rad 713 dLOsqXi_IFO = (Dntheta_IFO + Dptheta_IFO - 2*theta_IFO) / delta_LO_rad**2 714 #not clear the dXi_IFO is needed or calculated 715 ASbudget['lossMM'] = SQZ_Vsq - etaGamma_IFO 716 717 Xi_accum = Xi_IFO 718 719 def XiUpdate(fullXi, subXi): 720 subXi = subXi - 2 * fullXi * subXi 721 fullXi = fullXi + subXi 722 return fullXi, subXi 723 724 Xi_accum, Xi_SQZphase_noise = XiUpdate(Xi_accum, SQZ_angle_RMS**2) 725 Xi_accum, Xi_LOphase_noise = XiUpdate(Xi_accum, ((dLOtheta_IFO + 1) * LO_angle_RMS)**2) 726 727 ASbudget['SQZ'] = lambda : Vnorm_sq(LOa @ Hmats['AS'] @ olib.Mrotation(-SQZ_angle_rad) @ olib.SQZ(sqzV, asqzV)) SQZ_angle_rad
is defined negative to what it is on master. See here and note thatolib.Mrotation
has the same sign convention as that rotation matrix on master.
- test/BHD/test_quantum_BHD.py 0 → 100644
140 #ax.loglog(traces.freq, psd_full) 141 #fig.tight_layout() 142 #fig.savefig(tpath_join('test.pdf')) 143 R = inspiral_range.range(traces.freq, psd_full, **RANGE_PARAMS_NS) 144 pprint('Range:', R) 145 outNS[()] = R 146 R = inspiral_range.range(traces.freq, psd_full, **RANGE_PARAMS_BH) 147 pprint('Range:', R) 148 outBH[()] = R 149 contourNS = it.operands[2] 150 pprint(contourNS) 151 contourBH = it.operands[3] 152 pprint(contourBH) 153 154 import h5py 155 with h5py.File(tpath_join('contour.h5'), 'w') as hdf5: