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