Shifted discrete Fourier transform¶
Forward transform¶
We define the shifted discrete Fourier transform as
\[Z_k
\equiv
\sum_{n = 0}^{N - 1}
z_n
\twiddle{- 2 \pi}{\left( n + \frac{1}{2} \right) k}{N}
\equiv
\dft{k}{N}{z_0}{z_1}{z_{N - 1}},\]
where \(\seq{k}{0}{1}{N - 1}\).
Note
Since this relation leads to
\[Z_k
=
\twiddle{- \pi}{k}{N}
\sum_{n = 0}^{N - 1}
z_n
\twiddle{- 2 \pi}{n k}{N},\]
the shifted transform can be computed using the normal discrete Fourier transform followed by multiplication by a pre-factor.
By utilizing the decimation in time, the forward transform leads to
\[\begin{split}\begin{pmatrix}
Z_{k } \\
Z_{k + N / 2} \\
\end{pmatrix}
=
\begin{pmatrix}
\twiddle{\pi}{k}{N} & \twiddle{- \pi}{k}{N} \\
- I \twiddle{\pi}{k}{N} & I \twiddle{- \pi}{k}{N} \\
\end{pmatrix}
\begin{pmatrix}
\dft{k}{N / 2}{z_0}{z_2}{z_{N - 2}} \\
\dft{k}{N / 2}{z_1}{z_3}{z_{N - 1}} \\
\end{pmatrix}\end{split}\]
for \(\seq{k}{0}{1}{N / 2 - 1}\).
50static int sdft (
51 const size_t nitems,
52 const size_t stride,
53 const trig_t * const trigs,
54 const double complex * const xs,
55 double complex * const ys
56) {
57 if (1 == nitems) {
58 ys[0] = xs[0];
59 } else if (0 == nitems % 2) {
60 const size_t nh = nitems / 2;
61 // divide-and-conquer
62 sdft(nh, stride * 2, trigs, xs , ys );
63 sdft(nh, stride * 2, trigs, xs + stride, ys + nh);
64 // unify two sub problem results
65 for (size_t i = 0; i < nh; i++) {
66 const size_t j = i + nh;
67 const trig_t * const trig = trigs + stride * i;
68 const double complex twiddle[2] = {
69 trig->cos + I * trig->sin,
70 trig->cos - I * trig->sin,
71 };
72 double complex * const yi = ys + i;
73 double complex * const yj = ys + j;
74 const double complex ye = *yi;
75 const double complex yo = *yj;
76 *yi = twiddle[0] * ye + twiddle[1] * yo;
77 *yj = - I * twiddle[0] * ye + I * twiddle[1] * yo;
78 }
79 } else {
80 // naive O(N^2) sdft
81 for (size_t k = 0; k < nitems; k++) {
82 double complex * const y = ys + k;
83 *y = 0. + I * 0.;
84 for (size_t n = 0; n < nitems; n++) {
85 *y += xs[stride * n] * cexp(- 2. * pi * (n + 0.5) * k * I / nitems);
86 }
87 }
88 }
89 return 0;
90}
Backward transform¶
The inverse transform is defined as
\[z_n
=
\frac{1}{N}
\sum_{k = 0}^{N - 1}
Z_k
\twiddle{2 \pi}{\left( n + \frac{1}{2} \right) k}{N}
\equiv
\idft{n}{N}{Z_0}{Z_1}{Z_{N - 1}}.\]
Note
Due to
\[z_n
=
\frac{1}{N}
\sum_{k = 0}^{N - 1}
\left(
Z_k
\exp \left( \frac{\pi k}{N} I \right)
\right)
\twiddle{2 \pi}{n k}{N},\]
the inverse transform of a shifted signal can be computed using the normal inverse discrete Fourier transform where the input signal is multiplied by a pre-factor beforehand.
By utilizing the decimation in time, the inverse transform leads to
\[\begin{split}\begin{pmatrix}
z_{n } \\
z_{n + N / 2} \\
\end{pmatrix}
=
\begin{pmatrix}
\frac{1}{2} & \frac{1}{2} \twiddle{\pi}{2 n + 1}{N} \\
\frac{1}{2} & - \frac{1}{2} \twiddle{\pi}{2 n + 1}{N} \\
\end{pmatrix}
\begin{pmatrix}
\idft{n}{N / 2}{Z_0}{Z_2}{Z_{N - 2}} \\
\idft{n}{N / 2}{Z_1}{Z_3}{Z_{N - 1}} \\
\end{pmatrix}\end{split}\]
for \(\seq{n}{0}{1}{N / 2 - 1}\).
102static int isdft (
103 const size_t nitems,
104 const size_t stride,
105 const trig_t * const trigs,
106 const double complex * const xs,
107 double complex * const ys
108) {
109 if (1 == nitems) {
110 ys[0] = xs[0];
111 } else if (0 == nitems % 2) {
112 const size_t nh = nitems / 2;
113 // divide-and-conquer
114 isdft(nh, stride * 2, trigs, xs , ys );
115 isdft(nh, stride * 2, trigs, xs + stride, ys + nh);
116 // unify two sub problem results
117 for (size_t i = 0; i < nh; i++) {
118 const size_t j = i + nh;
119 const trig_t * const trig = trigs + (2 * i + 1) * stride;
120 const double complex twiddle = trig->cos + I * trig->sin;
121 double complex * const yi = ys + i;
122 double complex * const yj = ys + j;
123 const double complex ye = *yi;
124 const double complex yo = *yj;
125 *yi = 0.5 * ye + 0.5 * twiddle * yo;
126 *yj = 0.5 * ye - 0.5 * twiddle * yo;
127 }
128 } else {
129 // naive O(N^2) isdft
130 for (size_t n = 0; n < nitems; n++) {
131 double complex * const y = ys + n;
132 *y = 0. + I * 0.;
133 for (size_t k = 0; k < nitems; k++) {
134 *y += xs[stride * k] * cexp(2. * pi * (n + 0.5) * k * I / nitems);
135 }
136 *y /= nitems;
137 }
138 }
139 return 0;
140}