pdh_demo2.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #!/usr/bin/env python3
  2. import matplotlib
  3. import matplotlib.pyplot as plt
  4. from matplotlib import animation
  5. import numpy as np
  6. from numpy import cos, pi
  7. # matplotlib.rcParams.update({'font.size': 15})
  8. c = 3E8 # m/s
  9. L = 1.0 # m
  10. FSR = 2*pi*c/(2*L) # (rad/s)
  11. A0 = 1.0
  12. w0 = 1E1*FSR
  13. f0 = w0 / 2 / pi
  14. a_mod = 2
  15. w_mod = w0 / 3000
  16. f_mod = w_mod / 2 / pi
  17. def R_e(w):
  18. T = 0.25
  19. R = 1-T
  20. return 1 - T**2 / (1 + R**2 - 2*R*cos(w*2*L/c))
  21. def get_ref_power(freqs, powers):
  22. return sum(power*R_e(freq) for freq, power in zip(freqs, powers))
  23. def main3():
  24. N = 2000000
  25. ts = np.linspace(0, 10000*(1/f0), N)
  26. mod = a_mod*np.sin(w_mod*ts)
  27. Es = A0*np.cos((w0 + (-0.012)*FSR)*ts + mod)
  28. maxima = ts[np.r_[True, Es[1:] < Es[:-1]] &
  29. np.r_[Es[:-1] < Es[1:], True]]
  30. maxima = maxima[1:-1]
  31. n_periods = 100
  32. periods = (maxima[n_periods:] - maxima[:-n_periods])/n_periods
  33. centers = maxima[:-n_periods] + (periods/2)
  34. powers = R_e(2*pi/periods)
  35. freqs = (2*pi/periods - w0)/FSR
  36. def moving_average(a, n=3):
  37. ret = np.cumsum(a, dtype=float)
  38. ret[n:] = ret[n:] - ret[:-n]
  39. return ret[n - 1:] / n
  40. smooth = 25
  41. freqs = moving_average(freqs, n=smooth)
  42. powers = moving_average(powers, n=smooth)
  43. centers = centers[smooth-1:]
  44. Rs_ws = np.linspace(w0-0.5*FSR, w0+0.5*FSR, 300)
  45. Rs_Rs = R_e(Rs_ws)
  46. Rs_ws = (Rs_ws - w0)/FSR
  47. fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, ncols=1)
  48. n_frames = 300
  49. p_max = 0.16
  50. def do_plot(i):
  51. print(i)
  52. idx = int(i/n_frames * len(centers))
  53. t = centers[idx]
  54. f = freqs[idx]
  55. p = powers[idx]
  56. ax1.clear()
  57. ax1.plot(Rs_ws, Rs_Rs, 'b')
  58. ax1.plot([f], [p], 'r.')
  59. ax1.set_xlim((-0.1, 0.1))
  60. ax1.set_xlabel(r"$\Delta\omega(\mathrm{FSR})$")
  61. ax1.set_ylim((0, p_max))
  62. ax2.clear()
  63. ax2.plot(centers*f_mod, powers, 'b')
  64. ax2.set_ylabel('Refl. Power')
  65. ax2.set_ylim((0, p_max))
  66. ax2.set_xlim((0, ts[-1]*f_mod))
  67. ax2.set_xticks([])
  68. rect = plt.Rectangle((0, 0), t*f_mod, 1, facecolor='#aaaaaa')
  69. ax2.add_patch(rect)
  70. ax3.clear()
  71. ax3.plot(ts*f_mod, mod, 'r')
  72. ax3.set_ylabel('Modulation')
  73. ax3.set_ylim((-a_mod, a_mod))
  74. ax3.set_xlim((0, ts[-1]*f_mod))
  75. ax3.set_xlabel(r"$t(\tau_{\mathrm{mod}})$")
  76. rect = plt.Rectangle((0, -a_mod),
  77. t*f_mod, 2*a_mod, facecolor='#aaaaaa')
  78. ax3.add_patch(rect)
  79. # do_plot(0)
  80. # plt.show()
  81. anim = animation.FuncAnimation(fig, do_plot, n_frames)
  82. anim.save('output.mp4', fps=30, dpi=270)
  83. def main():
  84. N = 2000000
  85. ts = np.linspace(0, 10000*(1/f0), N)
  86. dt = ts[1]-ts[0]
  87. mod = a_mod*np.sin(w_mod*ts)
  88. Es = A0*np.cos(w0*ts + mod)
  89. print("FSR", FSR)
  90. print(1/f0, dt)
  91. n_groups = 100
  92. win_size = int((1/f_mod) / dt / 12)
  93. win_spacing = (N - win_size) // (n_groups-1)
  94. fig, (ax0, ax1, ax2) = plt.subplots(nrows=3, ncols=1)
  95. fig.set_tight_layout(True)
  96. Rs_ws = np.linspace(w0-0.5*FSR, w0+0.5*FSR, 300)
  97. Rs_Rs = R_e(Rs_ws)
  98. Rs_ws = (Rs_ws - w0)/FSR
  99. def do_plot(i):
  100. print(i)
  101. n = ts.size // n_groups
  102. win_start = i*win_spacing
  103. win_end = win_start + win_size
  104. # print(f"{win_start},{win_end}")
  105. # sec_ts = ts[win_start:win_end]
  106. sec = Es[win_start:win_end]
  107. # mod_sec = mod[win_start:win_end]
  108. sec_ft = np.fft.rfftn(sec)
  109. freq = 2*pi*np.fft.fftfreq(sec.size, d=dt)[:n//2]
  110. power = (sec_ft[:n//2]*sec_ft[:n//2].conj()).real / win_size
  111. # power = (sec_ft[:n//2].real**2 + sec_ft[:n//2].imag**2) / win_size
  112. ax0.plot(ts[(win_start+win_end) // 2],
  113. mod[(win_start+win_end) // 2], 'k.')
  114. ax0.set_ylim(-1.1*a_mod, 1.1*a_mod)
  115. ax0.set_xlim(0, ts[-1])
  116. ax1.clear()
  117. ax1.plot(freq/w0, power)
  118. ax1.set_xlim(0.80, 1.20)
  119. mean = np.average(freq, weights=power)
  120. print('{:2.2f} : {:2.2E}'.format((mean-w0)/FSR, R_e(mean*w0)))
  121. ax2.clear()
  122. ax2.plot(Rs_ws, Rs_Rs, 'b')
  123. ax2.plot((mean-w0)/FSR, R_e(mean), 'r.')
  124. ax2.set_xlim(-.5, .5)
  125. # ref_power = get_ref_power(freq, power)
  126. # ax2.plot(ts[(win_start+win_end) // 2], ref_power, 'r.')
  127. # ax2.set_xlim(0, ts[-1])
  128. anim = animation.FuncAnimation(fig, do_plot, n_groups)
  129. anim.save("output.mp4")
  130. if __name__ == '__main__':
  131. # main()
  132. # main2()
  133. main3()