waves.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. """
  2. This module has all the classes and functions related to waves in optics.
  3. **Contains**
  4. * TWave
  5. """
  6. __all__ = ['TWave']
  7. from sympy.core.basic import Basic
  8. from sympy.core.expr import Expr
  9. from sympy.core.function import Derivative, Function
  10. from sympy.core.numbers import (Number, pi, I)
  11. from sympy.core.singleton import S
  12. from sympy.core.symbol import (Symbol, symbols)
  13. from sympy.core.sympify import _sympify, sympify
  14. from sympy.functions.elementary.exponential import exp
  15. from sympy.functions.elementary.miscellaneous import sqrt
  16. from sympy.functions.elementary.trigonometric import (atan2, cos, sin)
  17. from sympy.physics.units import speed_of_light, meter, second
  18. c = speed_of_light.convert_to(meter/second)
  19. class TWave(Expr):
  20. r"""
  21. This is a simple transverse sine wave travelling in a one-dimensional space.
  22. Basic properties are required at the time of creation of the object,
  23. but they can be changed later with respective methods provided.
  24. Explanation
  25. ===========
  26. It is represented as :math:`A \times cos(k*x - \omega \times t + \phi )`,
  27. where :math:`A` is the amplitude, :math:`\omega` is the angular frequency,
  28. :math:`k` is the wavenumber (spatial frequency), :math:`x` is a spatial variable
  29. to represent the position on the dimension on which the wave propagates,
  30. and :math:`\phi` is the phase angle of the wave.
  31. Arguments
  32. =========
  33. amplitude : Sympifyable
  34. Amplitude of the wave.
  35. frequency : Sympifyable
  36. Frequency of the wave.
  37. phase : Sympifyable
  38. Phase angle of the wave.
  39. time_period : Sympifyable
  40. Time period of the wave.
  41. n : Sympifyable
  42. Refractive index of the medium.
  43. Raises
  44. =======
  45. ValueError : When neither frequency nor time period is provided
  46. or they are not consistent.
  47. TypeError : When anything other than TWave objects is added.
  48. Examples
  49. ========
  50. >>> from sympy import symbols
  51. >>> from sympy.physics.optics import TWave
  52. >>> A1, phi1, A2, phi2, f = symbols('A1, phi1, A2, phi2, f')
  53. >>> w1 = TWave(A1, f, phi1)
  54. >>> w2 = TWave(A2, f, phi2)
  55. >>> w3 = w1 + w2 # Superposition of two waves
  56. >>> w3
  57. TWave(sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + A2**2), f,
  58. atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2)), 1/f, n)
  59. >>> w3.amplitude
  60. sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + A2**2)
  61. >>> w3.phase
  62. atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2))
  63. >>> w3.speed
  64. 299792458*meter/(second*n)
  65. >>> w3.angular_velocity
  66. 2*pi*f
  67. """
  68. def __new__(
  69. cls,
  70. amplitude,
  71. frequency=None,
  72. phase=S.Zero,
  73. time_period=None,
  74. n=Symbol('n')):
  75. if time_period is not None:
  76. time_period = _sympify(time_period)
  77. _frequency = S.One/time_period
  78. if frequency is not None:
  79. frequency = _sympify(frequency)
  80. _time_period = S.One/frequency
  81. if time_period is not None:
  82. if frequency != S.One/time_period:
  83. raise ValueError("frequency and time_period should be consistent.")
  84. if frequency is None and time_period is None:
  85. raise ValueError("Either frequency or time period is needed.")
  86. if frequency is None:
  87. frequency = _frequency
  88. if time_period is None:
  89. time_period = _time_period
  90. amplitude = _sympify(amplitude)
  91. phase = _sympify(phase)
  92. n = sympify(n)
  93. obj = Basic.__new__(cls, amplitude, frequency, phase, time_period, n)
  94. return obj
  95. @property
  96. def amplitude(self):
  97. """
  98. Returns the amplitude of the wave.
  99. Examples
  100. ========
  101. >>> from sympy import symbols
  102. >>> from sympy.physics.optics import TWave
  103. >>> A, phi, f = symbols('A, phi, f')
  104. >>> w = TWave(A, f, phi)
  105. >>> w.amplitude
  106. A
  107. """
  108. return self.args[0]
  109. @property
  110. def frequency(self):
  111. """
  112. Returns the frequency of the wave,
  113. in cycles per second.
  114. Examples
  115. ========
  116. >>> from sympy import symbols
  117. >>> from sympy.physics.optics import TWave
  118. >>> A, phi, f = symbols('A, phi, f')
  119. >>> w = TWave(A, f, phi)
  120. >>> w.frequency
  121. f
  122. """
  123. return self.args[1]
  124. @property
  125. def phase(self):
  126. """
  127. Returns the phase angle of the wave,
  128. in radians.
  129. Examples
  130. ========
  131. >>> from sympy import symbols
  132. >>> from sympy.physics.optics import TWave
  133. >>> A, phi, f = symbols('A, phi, f')
  134. >>> w = TWave(A, f, phi)
  135. >>> w.phase
  136. phi
  137. """
  138. return self.args[2]
  139. @property
  140. def time_period(self):
  141. """
  142. Returns the temporal period of the wave,
  143. in seconds per cycle.
  144. Examples
  145. ========
  146. >>> from sympy import symbols
  147. >>> from sympy.physics.optics import TWave
  148. >>> A, phi, f = symbols('A, phi, f')
  149. >>> w = TWave(A, f, phi)
  150. >>> w.time_period
  151. 1/f
  152. """
  153. return self.args[3]
  154. @property
  155. def n(self):
  156. """
  157. Returns the refractive index of the medium
  158. """
  159. return self.args[4]
  160. @property
  161. def wavelength(self):
  162. """
  163. Returns the wavelength (spatial period) of the wave,
  164. in meters per cycle.
  165. It depends on the medium of the wave.
  166. Examples
  167. ========
  168. >>> from sympy import symbols
  169. >>> from sympy.physics.optics import TWave
  170. >>> A, phi, f = symbols('A, phi, f')
  171. >>> w = TWave(A, f, phi)
  172. >>> w.wavelength
  173. 299792458*meter/(second*f*n)
  174. """
  175. return c/(self.frequency*self.n)
  176. @property
  177. def speed(self):
  178. """
  179. Returns the propagation speed of the wave,
  180. in meters per second.
  181. It is dependent on the propagation medium.
  182. Examples
  183. ========
  184. >>> from sympy import symbols
  185. >>> from sympy.physics.optics import TWave
  186. >>> A, phi, f = symbols('A, phi, f')
  187. >>> w = TWave(A, f, phi)
  188. >>> w.speed
  189. 299792458*meter/(second*n)
  190. """
  191. return self.wavelength*self.frequency
  192. @property
  193. def angular_velocity(self):
  194. """
  195. Returns the angular velocity of the wave,
  196. in radians per second.
  197. Examples
  198. ========
  199. >>> from sympy import symbols
  200. >>> from sympy.physics.optics import TWave
  201. >>> A, phi, f = symbols('A, phi, f')
  202. >>> w = TWave(A, f, phi)
  203. >>> w.angular_velocity
  204. 2*pi*f
  205. """
  206. return 2*pi*self.frequency
  207. @property
  208. def wavenumber(self):
  209. """
  210. Returns the wavenumber of the wave,
  211. in radians per meter.
  212. Examples
  213. ========
  214. >>> from sympy import symbols
  215. >>> from sympy.physics.optics import TWave
  216. >>> A, phi, f = symbols('A, phi, f')
  217. >>> w = TWave(A, f, phi)
  218. >>> w.wavenumber
  219. pi*second*f*n/(149896229*meter)
  220. """
  221. return 2*pi/self.wavelength
  222. def __str__(self):
  223. """String representation of a TWave."""
  224. from sympy.printing import sstr
  225. return type(self).__name__ + sstr(self.args)
  226. __repr__ = __str__
  227. def __add__(self, other):
  228. """
  229. Addition of two waves will result in their superposition.
  230. The type of interference will depend on their phase angles.
  231. """
  232. if isinstance(other, TWave):
  233. if self.frequency == other.frequency and self.wavelength == other.wavelength:
  234. return TWave(sqrt(self.amplitude**2 + other.amplitude**2 + 2 *
  235. self.amplitude*other.amplitude*cos(
  236. self.phase - other.phase)),
  237. self.frequency,
  238. atan2(self.amplitude*sin(self.phase)
  239. + other.amplitude*sin(other.phase),
  240. self.amplitude*cos(self.phase)
  241. + other.amplitude*cos(other.phase))
  242. )
  243. else:
  244. raise NotImplementedError("Interference of waves with different frequencies"
  245. " has not been implemented.")
  246. else:
  247. raise TypeError(type(other).__name__ + " and TWave objects cannot be added.")
  248. def __mul__(self, other):
  249. """
  250. Multiplying a wave by a scalar rescales the amplitude of the wave.
  251. """
  252. other = sympify(other)
  253. if isinstance(other, Number):
  254. return TWave(self.amplitude*other, *self.args[1:])
  255. else:
  256. raise TypeError(type(other).__name__ + " and TWave objects cannot be multiplied.")
  257. def __sub__(self, other):
  258. return self.__add__(-1*other)
  259. def __neg__(self):
  260. return self.__mul__(-1)
  261. def __radd__(self, other):
  262. return self.__add__(other)
  263. def __rmul__(self, other):
  264. return self.__mul__(other)
  265. def __rsub__(self, other):
  266. return (-self).__radd__(other)
  267. def _eval_rewrite_as_sin(self, *args, **kwargs):
  268. return self.amplitude*sin(self.wavenumber*Symbol('x')
  269. - self.angular_velocity*Symbol('t') + self.phase + pi/2, evaluate=False)
  270. def _eval_rewrite_as_cos(self, *args, **kwargs):
  271. return self.amplitude*cos(self.wavenumber*Symbol('x')
  272. - self.angular_velocity*Symbol('t') + self.phase)
  273. def _eval_rewrite_as_pde(self, *args, **kwargs):
  274. mu, epsilon, x, t = symbols('mu, epsilon, x, t')
  275. E = Function('E')
  276. return Derivative(E(x, t), x, 2) + mu*epsilon*Derivative(E(x, t), t, 2)
  277. def _eval_rewrite_as_exp(self, *args, **kwargs):
  278. return self.amplitude*exp(I*(self.wavenumber*Symbol('x')
  279. - self.angular_velocity*Symbol('t') + self.phase))