code: def train_equaliser(
      E, TrSyms, Niter, os, mu, wx, modes, adaptive, symbols, method
  ):
      if method == "cma":
          errorfct = cma_error
  
      else:
          raise ValueError("Unknown method %s" % method)
      nmodes = E.shape[0]
      ntaps = wx.shape[-1]
      assert (
          symbols.shape[0] == nmodes
      ), "symbols must be at least size of modes"
      assert (
          wx.shape[0] == nmodes
      ), "wx needs to have at least as many dimensions as the maximum mode"
      assert (
          E.shape[1] > TrSyms * os + ntaps
      ), "Field must be longer than the number of training symbols"
      assert (
          modes.max() < nmodes
      ), "Maximum mode number must not be higher than number of modes"
      err = np.zeros((nmodes, TrSyms * Niter), dtype=E.dtype)
      # omp parallel for
      for mode in modes:
          for it in range(Niter):
              for i in range(TrSyms):
                  X = E[:, i * os : i * os + ntaps]
                  Xest = apply_filter(X, wx[mode])
                  err[mode, it * Niter + i] = errorfct(
                      Xest, symbols[mode], i
                  )
                  wx[mode] += (
                      mu * np.conj(err[mode, it * Niter + i]) * X
                  )
                  if adaptive and i > 0:
                      mu = adapt_step(
                          mu,
                          err[mode, it * Niter + i],
                          err[mode, it * Niter + i - 1],
                      )
      return err, wx, mu
  
imports: import numpy
label_desc: Use image node_id 1 for calling a global function with example usage: train_equaliser(E, TrSyms, Niter, os, mu, wx, modes, adaptive, symbols, method) and returns: err,  wx,  mu