code: def sample(problem, N, M=4, seed=None):
      """Generate model inputs for extended Fourier Amplitude Sensitivity Test.
  
      Returns a NumPy matrix containing the model inputs required by the extended
      Fourier Amplitude sensitivity test.  The resulting matrix contains N * D
      rows and D columns, where D is the number of parameters.
  
      The samples generated are intended to be used by
      :func:`SALib.analyze.fast.analyze`.
  
      Parameters
      ----------
      problem : dict
          The problem definition
      N : int
          The number of samples to generate
      M : int
          The interference parameter, i.e., the number of harmonics to sum in the
          Fourier series decomposition (default 4)
      seed : int
          Seed to generate a random number
  
      References
      ----------
      1. Cukier, R.I., Fortuin, C.M., Shuler, K.E., Petschek, A.G.,
         Schaibly, J.H., 1973.
         Study of the sensitivity of coupled reaction systems to
         uncertainties in rate coefficients. I theory.
         Journal of Chemical Physics 59, 3873-3878.
         https://doi.org/10.1063/1.1680571
  
      2. Saltelli, A., S. Tarantola, and K. P.-S. Chan (1999).
         A Quantitative Model-Independent Method for Global Sensitivity Analysis
         of Model Output.
         Technometrics, 41(1):39-56,
         doi:10.1080/00401706.1999.10485594.
      """
      if seed:
          np.random.seed(seed)
  
      if N <= 4 * M**2:
          raise ValueError(
              """
          Sample size N > 4M^2 is required. M=4 by default."""
          )
  
      D = problem["num_vars"]
  
      omega = np.zeros([D])
      omega[0] = math.floor((N - 1) / (2 * M))
      m = math.floor(omega[0] / (2 * M))
  
      if m >= (D - 1):
          omega[1:] = np.floor(np.linspace(1, m, D - 1))
      else:
          omega[1:] = np.arange(D - 1) % m + 1
  
      # Discretization of the frequency space, s
      s = (2 * math.pi / N) * np.arange(N)
  
      # Transformation to get points in the X space
      X = np.zeros([N * D, D])
      omega2 = np.zeros([D])
  
      for i in range(D):
          omega2[i] = omega[0]
          idx = list(range(i)) + list(range(i + 1, D))
          omega2[idx] = omega[1:]
          z = range(i * N, (i + 1) * N)
  
          # random phase shift on [0, 2pi) following Saltelli et al.
          # Technometrics 1999
          phi = 2 * math.pi * np.random.rand()
  
          for j in range(D):
              g = 0.5 + (1 / math.pi) * np.arcsin(
                  np.sin(omega2[j] * s + phi)
              )
              X[z, j] = g
  
      X = scale_samples(X, problem)
  
      return X
  
imports: import math
  import numpy
  from .None import common_args
  from ..util import scale_samples, read_param_file
label_desc: Use image node_id 1 for calling a global function with example usage: sample(problem, N, M, seed) and returns: X