0
$\begingroup$

my general idea is to

  1. Fourier transform some data
  2. Select out a few modes which meet certain criteria, by putting all other modes to zero
  3. Do an inverse Fourier transformation

The physics scenario could be to select only the modes with some given wave number.

Here is my implementation. I'm using a two-dimensional example but ultimately my data is 3D.

(* generate data *)
n = 16;
l = RandomReal[{-1, 1}, {n, n}];

(* define the wave vectors *)
kx = {Range[0, n/2 - 1], Range[-n/2, -1]} // Flatten // N;
kvec = Outer[List, kx, kx];

(* compute the norm of each wave vector *)
knorm = Map[Round@*Norm, kvec, {2}];

(* let's say we want to filter out the wave number = 3 modes *)
p = 3;

(* find out where the modes are *)
pos = Position[knorm, p];

(* using the factor g to make all other modes 0 *)
g = ConstantArray[0, {n, n}] // ReplacePart[#, pos -> 1] &;
Re@InverseFourier[g*Fourier[l]]

Altogether I can write some function like

Clear[fourierFilter]
fourierFilter[l_, p_] := Module[{n, kx, knorm, pos, g},
  n = Dimensions[l][[1]];
  kx = {Range[0, n/2 - 1], Range[-n/2, -1]} // Flatten // N;
  knorm = Map[Round@*Norm, Outer[List, kx, kx], {2}];
  
  pos = Position[knorm, p];
  g = ConstantArray[0, {n, n}] // ReplacePart[#, pos -> 1] &;
  Re@InverseFourier[g*Fourier[l]]
  ]

Is there a better way to implement the idea, either in terms of time or memory efficiency? I know Fourier can take a second argument which specifies which mode I want, but I'm not sure if there is a straightforward way to inverse transform with these selected modes. I tried to do that by hand but it turns out to be slower than the implementation above.

$\endgroup$

1 Answer 1

1
$\begingroup$

Note: I am guessing that in the 3D situation that OP has, a Fourier-based approach will probably be best. I provide another approach, just for comparison.

Here is an approach that does not use Fourier, except in a preliminary step. This will be competitive if only very few modes meet the criterium, i.e. if pos is short. Note that I implicitly make assumptions about what kind of filter one has. It works in the example that OP provides, I did not check beyond that.

Here is the code, and I assume the first code block provided by OP has already been evaluated:

(* construct auxiliary matrix, this is a preliminary step
   I made not effort at all to make this fast
   one can check that P.Transpose[P] is the identity matrix *)
P=With[{aux=Map[Flatten[Fourier[ReplacePart[ConstantArray[0.,{n,n}],#->1]]]&,pos]},
    Re[MatrixPower[aux.Transpose[aux],-1/2].aux]];

(* two filters *)
filterOP[x_]:=Re[InverseFourier[g*Fourier[x]]];
filterNew[x_]:=ArrayReshape[(P.Flatten[x]).P,{n,n}];

(* check that they give the same result *)
Chop[Norm[filterOP[l]-filterNew[l]]]
(* 0 *)

(* timing *)
RepeatedTiming[filterOP[l];]
(* about 0.000012 *)
RepeatedTiming[filterNew[l];]
(* about 0.000005 *)

It is slightly faster in this case.

Note. I have assumed that the construction of g in OPs code, and the construction of P in my code, is not part of the timing. Whether they should be part of the timing depends on the situation.

$\endgroup$
3
  • $\begingroup$ Thanks for your answer! Could you explain why your method is faster? $\endgroup$
    – H. Zhou
    Commented Aug 18, 2022 at 17:23
  • $\begingroup$ Your filter is an orthogonal projection. Hence it can be written as $P^T P$ for some rectangular matrix $P$ with $PP^T = \mathbb{1}$. The matrix $P$ has size $r \times N$ where $r$ is the rank (equal to Length[pos], the number of modes that are kept) and $N$ the dimension ($N = n^2$ in your 2D example). Essentially, each row of $P$ is a unit vector corresponding to one mode that you keep. If $r$ is small, then multiplying with $P^T P$ (meaning first with $P$, which gives a vector of length $r$, then with $P^T$) can be fast. $\endgroup$
    – user293787
    Commented Aug 18, 2022 at 17:42
  • $\begingroup$ But I would not have known without trying. And if the parameters are changed, it may well be slower than your method! Let us hope that some other people join the discussion, preferably somebody with signal processing experience. Please keep in mind that I wrote this code very quickly, so please be careful if you end up using it. $\endgroup$
    – user293787
    Commented Aug 18, 2022 at 17:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.