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