Chris@10: (* Chris@10: * Copyright (c) 1997-1999 Massachusetts Institute of Technology Chris@10: * Copyright (c) 2003, 2007-11 Matteo Frigo Chris@10: * Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology Chris@10: * Chris@10: * This program is free software; you can redistribute it and/or modify Chris@10: * it under the terms of the GNU General Public License as published by Chris@10: * the Free Software Foundation; either version 2 of the License, or Chris@10: * (at your option) any later version. Chris@10: * Chris@10: * This program is distributed in the hope that it will be useful, Chris@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@10: * GNU General Public License for more details. Chris@10: * Chris@10: * You should have received a copy of the GNU General Public License Chris@10: * along with this program; if not, write to the Free Software Chris@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Chris@10: * Chris@10: *) Chris@10: Chris@10: (* trigonometric transforms *) Chris@10: open Util Chris@10: Chris@10: (* DFT of real input *) Chris@10: let rdft sign n input = Chris@10: Fft.dft sign n (Complex.real @@ input) Chris@10: Chris@10: (* DFT of hermitian input *) Chris@10: let hdft sign n input = Chris@10: Fft.dft sign n (Complex.hermitian n input) Chris@10: Chris@10: (* DFT real transform of vectors of two real numbers, Chris@10: multiplication by (NaN I), and summation *) Chris@10: let dft_via_rdft sign n input = Chris@10: let f = rdft sign n input Chris@10: in fun i -> Chris@10: Complex.plus Chris@10: [Complex.real (f i); Chris@10: Complex.times (Complex.nan Expr.I) (Complex.imag (f i))] Chris@10: Chris@10: (* Discrete Hartley Transform *) Chris@10: let dht sign n input = Chris@10: let f = Fft.dft sign n (Complex.real @@ input) in Chris@10: (fun i -> Chris@10: Complex.plus [Complex.real (f i); Complex.imag (f i)]) Chris@10: Chris@10: let trigI n input = Chris@10: let twon = 2 * n in Chris@10: let input' = Complex.hermitian twon input Chris@10: in Chris@10: Fft.dft 1 twon input' Chris@10: Chris@10: let interleave_zero input = fun i -> Chris@10: if (i mod 2) == 0 Chris@10: then Complex.zero Chris@10: else Chris@10: input ((i - 1) / 2) Chris@10: Chris@10: let trigII n input = Chris@10: let fourn = 4 * n in Chris@10: let input' = Complex.hermitian fourn (interleave_zero input) Chris@10: in Chris@10: Fft.dft 1 fourn input' Chris@10: Chris@10: let trigIII n input = Chris@10: let fourn = 4 * n in Chris@10: let twon = 2 * n in Chris@10: let input' = Complex.hermitian fourn Chris@10: (fun i -> Chris@10: if (i == 0) then Chris@10: Complex.real (input 0) Chris@10: else if (i == twon) then Chris@10: Complex.uminus (Complex.real (input 0)) Chris@10: else Chris@10: Complex.antihermitian twon input i) Chris@10: in Chris@10: let dft = Fft.dft 1 fourn input' Chris@10: in fun k -> dft (2 * k + 1) Chris@10: Chris@10: let zero_extend n input = fun i -> Chris@10: if (i >= 0 && i < n) Chris@10: then input i Chris@10: else Complex.zero Chris@10: Chris@10: let trigIV n input = Chris@10: let fourn = 4 * n Chris@10: and eightn = 8 * n in Chris@10: let input' = Complex.hermitian eightn Chris@10: (zero_extend fourn (Complex.antihermitian fourn Chris@10: (interleave_zero input))) Chris@10: in Chris@10: let dft = Fft.dft 1 eightn input' Chris@10: in fun k -> dft (2 * k + 1) Chris@10: Chris@10: let make_dct scale nshift trig = Chris@10: fun n input -> Chris@10: trig (n - nshift) (Complex.real @@ (Complex.times scale) @@ Chris@10: (zero_extend n input)) Chris@10: (* Chris@10: * DCT-I: y[k] = sum x[j] cos(pi * j * k / n) Chris@10: *) Chris@10: let dctI = make_dct Complex.one 1 trigI Chris@10: Chris@10: (* Chris@10: * DCT-II: y[k] = sum x[j] cos(pi * (j + 1/2) * k / n) Chris@10: *) Chris@10: let dctII = make_dct Complex.one 0 trigII Chris@10: Chris@10: (* Chris@10: * DCT-III: y[k] = sum x[j] cos(pi * j * (k + 1/2) / n) Chris@10: *) Chris@10: let dctIII = make_dct Complex.half 0 trigIII Chris@10: Chris@10: (* Chris@10: * DCT-IV y[k] = sum x[j] cos(pi * (j + 1/2) * (k + 1/2) / n) Chris@10: *) Chris@10: let dctIV = make_dct Complex.half 0 trigIV Chris@10: Chris@10: let shift s input = fun i -> input (i - s) Chris@10: Chris@10: (* DST-x input := TRIG-x (input / i) *) Chris@10: let make_dst scale nshift kshift jshift trig = Chris@10: fun n input -> Chris@10: Complex.real @@ Chris@10: (shift (- jshift) Chris@10: (trig (n + nshift) (Complex.uminus @@ Chris@10: (Complex.times Complex.i) @@ Chris@10: (Complex.times scale) @@ Chris@10: Complex.real @@ Chris@10: (shift kshift (zero_extend n input))))) Chris@10: Chris@10: (* Chris@10: * DST-I: y[k] = sum x[j] sin(pi * j * k / n) Chris@10: *) Chris@10: let dstI = make_dst Complex.one 1 1 1 trigI Chris@10: Chris@10: (* Chris@10: * DST-II: y[k] = sum x[j] sin(pi * (j + 1/2) * k / n) Chris@10: *) Chris@10: let dstII = make_dst Complex.one 0 0 1 trigII Chris@10: Chris@10: (* Chris@10: * DST-III: y[k] = sum x[j] sin(pi * j * (k + 1/2) / n) Chris@10: *) Chris@10: let dstIII = make_dst Complex.half 0 1 0 trigIII Chris@10: Chris@10: (* Chris@10: * DST-IV y[k] = sum x[j] sin(pi * (j + 1/2) * (k + 1/2) / n) Chris@10: *) Chris@10: let dstIV = make_dst Complex.half 0 0 0 trigIV Chris@10: