blob: 28d7fceee0e143fd07ed0d0bc169be343e444d6e [file] [log] [blame]
Raymonddee08492015-04-02 10:43:13 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17package org.apache.commons.math.transform;
18
19import org.apache.commons.math.FunctionEvaluationException;
20import org.apache.commons.math.MathRuntimeException;
21import org.apache.commons.math.analysis.UnivariateRealFunction;
22import org.apache.commons.math.complex.Complex;
23import org.apache.commons.math.exception.util.LocalizedFormats;
24import org.apache.commons.math.util.FastMath;
25
26/**
27 * Implements the <a href="http://documents.wolfram.com/v5/Add-onsLinks/
28 * StandardPackages/LinearAlgebra/FourierTrig.html">Fast Sine Transform</a>
29 * for transformation of one-dimensional data sets. For reference, see
30 * <b>Fast Fourier Transforms</b>, ISBN 0849371635, chapter 3.
31 * <p>
32 * FST is its own inverse, up to a multiplier depending on conventions.
33 * The equations are listed in the comments of the corresponding methods.</p>
34 * <p>
35 * Similar to FFT, we also require the length of data set to be power of 2.
36 * In addition, the first element must be 0 and it's enforced in function
37 * transformation after sampling.</p>
38 * <p>As of version 2.0 this no longer implements Serializable</p>
39 *
40 * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
41 * @since 1.2
42 */
43public class FastSineTransformer implements RealTransformer {
44
45 /**
46 * Construct a default transformer.
47 */
48 public FastSineTransformer() {
49 super();
50 }
51
52 /**
53 * Transform the given real data set.
54 * <p>
55 * The formula is F<sub>n</sub> = &sum;<sub>k=0</sub><sup>N-1</sup> f<sub>k</sub> sin(&pi; nk/N)
56 * </p>
57 *
58 * @param f the real data array to be transformed
59 * @return the real transformed array
60 * @throws IllegalArgumentException if any parameters are invalid
61 */
62 public double[] transform(double f[])
63 throws IllegalArgumentException {
64 return fst(f);
65 }
66
67 /**
68 * Transform the given real function, sampled on the given interval.
69 * <p>
70 * The formula is F<sub>n</sub> = &sum;<sub>k=0</sub><sup>N-1</sup> f<sub>k</sub> sin(&pi; nk/N)
71 * </p>
72 *
73 * @param f the function to be sampled and transformed
74 * @param min the lower bound for the interval
75 * @param max the upper bound for the interval
76 * @param n the number of sample points
77 * @return the real transformed array
78 * @throws FunctionEvaluationException if function cannot be evaluated
79 * at some point
80 * @throws IllegalArgumentException if any parameters are invalid
81 */
82 public double[] transform(UnivariateRealFunction f,
83 double min, double max, int n)
84 throws FunctionEvaluationException, IllegalArgumentException {
85
86 double data[] = FastFourierTransformer.sample(f, min, max, n);
87 data[0] = 0.0;
88 return fst(data);
89 }
90
91 /**
92 * Transform the given real data set.
93 * <p>
94 * The formula is F<sub>n</sub> = &radic;(2/N) &sum;<sub>k=0</sub><sup>N-1</sup> f<sub>k</sub> sin(&pi; nk/N)
95 * </p>
96 *
97 * @param f the real data array to be transformed
98 * @return the real transformed array
99 * @throws IllegalArgumentException if any parameters are invalid
100 */
101 public double[] transform2(double f[]) throws IllegalArgumentException {
102
103 double scaling_coefficient = FastMath.sqrt(2.0 / f.length);
104 return FastFourierTransformer.scaleArray(fst(f), scaling_coefficient);
105 }
106
107 /**
108 * Transform the given real function, sampled on the given interval.
109 * <p>
110 * The formula is F<sub>n</sub> = &radic;(2/N) &sum;<sub>k=0</sub><sup>N-1</sup> f<sub>k</sub> sin(&pi; nk/N)
111 * </p>
112 *
113 * @param f the function to be sampled and transformed
114 * @param min the lower bound for the interval
115 * @param max the upper bound for the interval
116 * @param n the number of sample points
117 * @return the real transformed array
118 * @throws FunctionEvaluationException if function cannot be evaluated
119 * at some point
120 * @throws IllegalArgumentException if any parameters are invalid
121 */
122 public double[] transform2(
123 UnivariateRealFunction f, double min, double max, int n)
124 throws FunctionEvaluationException, IllegalArgumentException {
125
126 double data[] = FastFourierTransformer.sample(f, min, max, n);
127 data[0] = 0.0;
128 double scaling_coefficient = FastMath.sqrt(2.0 / n);
129 return FastFourierTransformer.scaleArray(fst(data), scaling_coefficient);
130 }
131
132 /**
133 * Inversely transform the given real data set.
134 * <p>
135 * The formula is f<sub>k</sub> = (2/N) &sum;<sub>n=0</sub><sup>N-1</sup> F<sub>n</sub> sin(&pi; nk/N)
136 * </p>
137 *
138 * @param f the real data array to be inversely transformed
139 * @return the real inversely transformed array
140 * @throws IllegalArgumentException if any parameters are invalid
141 */
142 public double[] inversetransform(double f[]) throws IllegalArgumentException {
143
144 double scaling_coefficient = 2.0 / f.length;
145 return FastFourierTransformer.scaleArray(fst(f), scaling_coefficient);
146 }
147
148 /**
149 * Inversely transform the given real function, sampled on the given interval.
150 * <p>
151 * The formula is f<sub>k</sub> = (2/N) &sum;<sub>n=0</sub><sup>N-1</sup> F<sub>n</sub> sin(&pi; nk/N)
152 * </p>
153 *
154 * @param f the function to be sampled and inversely transformed
155 * @param min the lower bound for the interval
156 * @param max the upper bound for the interval
157 * @param n the number of sample points
158 * @return the real inversely transformed array
159 * @throws FunctionEvaluationException if function cannot be evaluated at some point
160 * @throws IllegalArgumentException if any parameters are invalid
161 */
162 public double[] inversetransform(UnivariateRealFunction f, double min, double max, int n)
163 throws FunctionEvaluationException, IllegalArgumentException {
164
165 double data[] = FastFourierTransformer.sample(f, min, max, n);
166 data[0] = 0.0;
167 double scaling_coefficient = 2.0 / n;
168 return FastFourierTransformer.scaleArray(fst(data), scaling_coefficient);
169 }
170
171 /**
172 * Inversely transform the given real data set.
173 * <p>
174 * The formula is f<sub>k</sub> = &radic;(2/N) &sum;<sub>n=0</sub><sup>N-1</sup> F<sub>n</sub> sin(&pi; nk/N)
175 * </p>
176 *
177 * @param f the real data array to be inversely transformed
178 * @return the real inversely transformed array
179 * @throws IllegalArgumentException if any parameters are invalid
180 */
181 public double[] inversetransform2(double f[]) throws IllegalArgumentException {
182
183 return transform2(f);
184 }
185
186 /**
187 * Inversely transform the given real function, sampled on the given interval.
188 * <p>
189 * The formula is f<sub>k</sub> = &radic;(2/N) &sum;<sub>n=0</sub><sup>N-1</sup> F<sub>n</sub> sin(&pi; nk/N)
190 * </p>
191 *
192 * @param f the function to be sampled and inversely transformed
193 * @param min the lower bound for the interval
194 * @param max the upper bound for the interval
195 * @param n the number of sample points
196 * @return the real inversely transformed array
197 * @throws FunctionEvaluationException if function cannot be evaluated at some point
198 * @throws IllegalArgumentException if any parameters are invalid
199 */
200 public double[] inversetransform2(UnivariateRealFunction f, double min, double max, int n)
201 throws FunctionEvaluationException, IllegalArgumentException {
202
203 return transform2(f, min, max, n);
204 }
205
206 /**
207 * Perform the FST algorithm (including inverse).
208 *
209 * @param f the real data array to be transformed
210 * @return the real transformed array
211 * @throws IllegalArgumentException if any parameters are invalid
212 */
213 protected double[] fst(double f[]) throws IllegalArgumentException {
214
215 final double transformed[] = new double[f.length];
216
217 FastFourierTransformer.verifyDataSet(f);
218 if (f[0] != 0.0) {
219 throw MathRuntimeException.createIllegalArgumentException(
220 LocalizedFormats.FIRST_ELEMENT_NOT_ZERO,
221 f[0]);
222 }
223 final int n = f.length;
224 if (n == 1) { // trivial case
225 transformed[0] = 0.0;
226 return transformed;
227 }
228
229 // construct a new array and perform FFT on it
230 final double[] x = new double[n];
231 x[0] = 0.0;
232 x[n >> 1] = 2.0 * f[n >> 1];
233 for (int i = 1; i < (n >> 1); i++) {
234 final double a = FastMath.sin(i * FastMath.PI / n) * (f[i] + f[n-i]);
235 final double b = 0.5 * (f[i] - f[n-i]);
236 x[i] = a + b;
237 x[n - i] = a - b;
238 }
239 FastFourierTransformer transformer = new FastFourierTransformer();
240 Complex y[] = transformer.transform(x);
241
242 // reconstruct the FST result for the original array
243 transformed[0] = 0.0;
244 transformed[1] = 0.5 * y[0].getReal();
245 for (int i = 1; i < (n >> 1); i++) {
246 transformed[2 * i] = -y[i].getImaginary();
247 transformed[2 * i + 1] = y[i].getReal() + transformed[2 * i - 1];
248 }
249
250 return transformed;
251 }
252}