code: def orbital_phantom(
      gtab=None,
      evals=diffusion_evals,
      func=None,
      t=np.linspace(0, 2 * np.pi, 1000),
      datashape=(64, 64, 64, 65),
      origin=(32, 32, 32),
      scale=(25, 25, 25),
      angles=np.linspace(0, 2 * np.pi, 32),
      radii=np.linspace(0.2, 2, 6),
      S0=100.0,
      snr=None,
      rng=None,
  ):
      """Create a phantom based on a 3-D orbit ``f(t) -> (x,y,z)``.
  
      Parameters
      ----------
      gtab : GradientTable
          Gradient table of measurement directions.
      evals : array, shape (3,)
          Tensor eigenvalues.
      func : user defined function f(t)->(x,y,z)
          It could be desirable for ``-1=<x,y,z <=1``.
          If None creates a circular orbit.
      t : array, shape (K,)
          Represents time for the orbit. Default is
          ``np.linspace(0, 2 * np.pi, 1000)``.
      datashape : array, shape (X,Y,Z,W)
          Size of the output simulated data
      origin : tuple, shape (3,)
          Define the center for the volume
      scale : tuple, shape (3,)
          Scale the function before applying to the grid
      angles : array, shape (L,)
          Density angle points, always perpendicular to the first eigen vector
          Default np.linspace(0, 2 * np.pi, 32).
      radii : array, shape (M,)
          Thickness radii.  Default ``np.linspace(0.2, 2, 6)``.
          angles and radii define the total thickness options
      S0 : double, optional
          Maximum simulated signal. Default 100.
      snr : float, optional
          The signal to noise ratio set to apply Rician noise to the data.
          Default is to not add noise at all.
      rng : numpy.random.Generator class, optional
          Numpy's random generator for setting seed values when needed.
          Default is None.
  
      Returns
      -------
      data : array, shape (datashape)
  
      See Also
      --------
      add_noise
  
      Examples
      --------
  
      >>> def f(t):
      ...    x = np.sin(t)
      ...    y = np.cos(t)
      ...    z = np.linspace(-1, 1, len(x))
      ...    return x, y, z
  
      >>> data = orbital_phantom(func=f)
  
      """
  
      if gtab is None:
          fimg, fbvals, fbvecs = get_fnames("small_64D")
          gtab = gradient_table(fbvals, fbvecs)
  
      if func is None:
          x = np.sin(t)
          y = np.cos(t)
          z = np.zeros(t.shape)
      else:
          x, y, z = func(t)
  
      dx = np.diff(x)
      dy = np.diff(y)
      dz = np.diff(z)
  
      x = scale[0] * x + origin[0]
      y = scale[1] * y + origin[1]
      z = scale[2] * z + origin[2]
  
      bx = np.zeros(len(angles))
      by = np.sin(angles)
      bz = np.cos(angles)
  
      # The entire volume is considered to be inside the brain.
      # Voxels without a fiber crossing through them are taken
      # to be isotropic with signal = S0.
      vol = np.zeros(datashape) + S0
  
      for i in range(len(dx)):
          evecs, R = diff2eigenvectors(dx[i], dy[i], dz[i])
          S = single_tensor(gtab, S0, evals, evecs, snr=None)
  
          vol[int(x[i]), int(y[i]), int(z[i]), :] += S
  
          for r in radii:
              for j in range(len(angles)):
                  rb = np.dot(R, np.array([bx[j], by[j], bz[j]]))
  
                  ix = int(x[i] + r * rb[0])
                  iy = int(y[i] + r * rb[1])
                  iz = int(z[i] + r * rb[2])
                  vol[ix, iy, iz] = vol[ix, iy, iz] + S
  
      vol = vol / np.max(vol, axis=-1)[..., np.newaxis]
      vol *= S0
  
      if snr is not None:
          vol = add_noise(vol, snr, S0=S0, noise_type="rician", rng=rng)
  
      return vol
  
file_path: dipy/dipy/sims/phantom.py
imports: import numpy
  from dipy.sims.voxel import single_tensor, diffusion_evals
  import dipy.sims.voxel
  from dipy.core.geometry import vec2vec_rotmat
  from dipy.data import get_fnames
  from dipy.core.gradients import gradient_table
label_desc: Use image node_id 3 for calling a global function with example usage: orbital_phantom(gtab, evals, func, t, datashape, origin, scale, angles, radii, S0, snr, rng) and returns: vol