1 /*
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 */
17 package org.apache.commons.math.transform;
18
19 import java.io.Serializable;
20 import org.apache.commons.math.analysis.*;
21 import org.apache.commons.math.complex.*;
22 import org.apache.commons.math.MathException;
23
24 /**
25 * Implements the <a href="http://documents.wolfram.com/v5/Add-onsLinks/
26 * StandardPackages/LinearAlgebra/FourierTrig.html">Fast Sine Transform</a>
27 * for transformation of one-dimensional data sets. For reference, see
28 * <b>Fast Fourier Transforms</b>, ISBN 0849371635, chapter 3.
29 * <p>
30 * FST is its own inverse, up to a multiplier depending on conventions.
31 * The equations are listed in the comments of the corresponding methods.</p>
32 * <p>
33 * Similar to FFT, we also require the length of data set to be power of 2.
34 * In addition, the first element must be 0 and it's enforced in function
35 * transformation after sampling.</p>
36 *
37 * @version $Revision: 620312 $ $Date: 2008-02-10 12:28:59 -0700 (Sun, 10 Feb 2008) $
38 * @since 1.2
39 */
40 public class FastSineTransformer implements Serializable {
41
42 /** serializable version identifier */
43 static final long serialVersionUID = -478002039949390854L;
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_n = \Sigma_{k=0}^{N-1} f_k \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 MathException if any math-related errors occur
61 * @throws IllegalArgumentException if any parameters are invalid
62 */
63 public double[] transform(double f[]) throws MathException,
64 IllegalArgumentException {
65
66 return fst(f);
67 }
68
69 /**
70 * Transform the given real function, sampled on the given interval.
71 * <p>
72 * The formula is $ F_n = \Sigma_{k=0}^{N-1} f_k \sin(\pi nk/N) $
73 * </p>
74 *
75 * @param f the function to be sampled and transformed
76 * @param min the lower bound for the interval
77 * @param max the upper bound for the interval
78 * @param n the number of sample points
79 * @return the real transformed array
80 * @throws MathException if any math-related errors occur
81 * @throws IllegalArgumentException if any parameters are invalid
82 */
83 public double[] transform(
84 UnivariateRealFunction f, double min, double max, int n)
85 throws MathException, IllegalArgumentException {
86
87 double data[] = FastFourierTransformer.sample(f, min, max, n);
88 data[0] = 0.0;
89 return fst(data);
90 }
91
92 /**
93 * Transform the given real data set.
94 * <p>
95 * The formula is $ F_n = \sqrt{2/N} \Sigma_{k=0}^{N-1} f_k \sin(\pi nk/N) $
96 * </p>
97 *
98 * @param f the real data array to be transformed
99 * @return the real transformed array
100 * @throws MathException if any math-related errors occur
101 * @throws IllegalArgumentException if any parameters are invalid
102 */
103 public double[] transform2(double f[]) throws MathException,
104 IllegalArgumentException {
105
106 double scaling_coefficient = Math.sqrt(2.0 / f.length);
107 return FastFourierTransformer.scaleArray(fst(f), scaling_coefficient);
108 }
109
110 /**
111 * Transform the given real function, sampled on the given interval.
112 * <p>
113 * The formula is $ F_n = \sqrt{2/N} \Sigma_{k=0}^{N-1} f_k \sin(\pi nk/N) $
114 * </p>
115 *
116 * @param f the function to be sampled and transformed
117 * @param min the lower bound for the interval
118 * @param max the upper bound for the interval
119 * @param n the number of sample points
120 * @return the real transformed array
121 * @throws MathException if any math-related errors occur
122 * @throws IllegalArgumentException if any parameters are invalid
123 */
124 public double[] transform2(
125 UnivariateRealFunction f, double min, double max, int n)
126 throws MathException, IllegalArgumentException {
127
128 double data[] = FastFourierTransformer.sample(f, min, max, n);
129 data[0] = 0.0;
130 double scaling_coefficient = Math.sqrt(2.0 / n);
131 return FastFourierTransformer.scaleArray(fst(data), scaling_coefficient);
132 }
133
134 /**
135 * Inversely transform the given real data set.
136 * <p>
137 * The formula is $ f_k = (2/N) \Sigma_{n=0}^{N-1} F_n \sin(\pi nk/N) $
138 * </p>
139 *
140 * @param f the real data array to be inversely transformed
141 * @return the real inversely transformed array
142 * @throws MathException if any math-related errors occur
143 * @throws IllegalArgumentException if any parameters are invalid
144 */
145 public double[] inversetransform(double f[]) throws MathException,
146 IllegalArgumentException {
147
148 double scaling_coefficient = 2.0 / f.length;
149 return FastFourierTransformer.scaleArray(fst(f), scaling_coefficient);
150 }
151
152 /**
153 * Inversely transform the given real function, sampled on the given interval.
154 * <p>
155 * The formula is $ f_k = (2/N) \Sigma_{n=0}^{N-1} F_n \sin(\pi nk/N) $
156 * </p>
157 *
158 * @param f the function to be sampled and inversely transformed
159 * @param min the lower bound for the interval
160 * @param max the upper bound for the interval
161 * @param n the number of sample points
162 * @return the real inversely transformed array
163 * @throws MathException if any math-related errors occur
164 * @throws IllegalArgumentException if any parameters are invalid
165 */
166 public double[] inversetransform(
167 UnivariateRealFunction f, double min, double max, int n)
168 throws MathException, IllegalArgumentException {
169
170 double data[] = FastFourierTransformer.sample(f, min, max, n);
171 data[0] = 0.0;
172 double scaling_coefficient = 2.0 / n;
173 return FastFourierTransformer.scaleArray(fst(data), scaling_coefficient);
174 }
175
176 /**
177 * Inversely transform the given real data set.
178 * <p>
179 * The formula is $ f_k = \sqrt{2/N} \Sigma_{n=0}^{N-1} F_n \sin(\pi nk/N) $
180 * </p>
181 *
182 * @param f the real data array to be inversely transformed
183 * @return the real inversely transformed array
184 * @throws MathException if any math-related errors occur
185 * @throws IllegalArgumentException if any parameters are invalid
186 */
187 public double[] inversetransform2(double f[]) throws MathException,
188 IllegalArgumentException {
189
190 return transform2(f);
191 }
192
193 /**
194 * Inversely transform the given real function, sampled on the given interval.
195 * <p>
196 * The formula is $ f_k = \sqrt{2/N} \Sigma_{n=0}^{N-1} F_n \sin(\pi nk/N) $
197 * </p>
198 *
199 * @param f the function to be sampled and inversely transformed
200 * @param min the lower bound for the interval
201 * @param max the upper bound for the interval
202 * @param n the number of sample points
203 * @return the real inversely transformed array
204 * @throws MathException if any math-related errors occur
205 * @throws IllegalArgumentException if any parameters are invalid
206 */
207 public double[] inversetransform2(
208 UnivariateRealFunction f, double min, double max, int n)
209 throws MathException, IllegalArgumentException {
210
211 return transform2(f, min, max, n);
212 }
213
214 /**
215 * Perform the FST algorithm (including inverse).
216 *
217 * @param f the real data array to be transformed
218 * @return the real transformed array
219 * @throws MathException if any math-related errors occur
220 * @throws IllegalArgumentException if any parameters are invalid
221 */
222 protected double[] fst(double f[]) throws MathException,
223 IllegalArgumentException {
224
225 double A, B, x[], F[] = new double[f.length];
226
227 FastFourierTransformer.verifyDataSet(f);
228 if (f[0] != 0.0) {
229 throw new IllegalArgumentException
230 ("The first element is not zero: " + f[0]);
231 }
232 int N = f.length;
233 if (N == 1) { // trivial case
234 F[0] = 0.0;
235 return F;
236 }
237
238 // construct a new array and perform FFT on it
239 x = new double[N];
240 x[0] = 0.0;
241 x[N >> 1] = 2.0 * f[N >> 1];
242 for (int i = 1; i < (N >> 1); i++) {
243 A = Math.sin(i * Math.PI / N) * (f[i] + f[N-i]);
244 B = 0.5 * (f[i] - f[N-i]);
245 x[i] = A + B;
246 x[N-i] = A - B;
247 }
248 FastFourierTransformer transformer = new FastFourierTransformer();
249 Complex y[] = transformer.transform(x);
250
251 // reconstruct the FST result for the original array
252 F[0] = 0.0;
253 F[1] = 0.5 * y[0].getReal();
254 for (int i = 1; i < (N >> 1); i++) {
255 F[2*i] = -y[i].getImaginary();
256 F[2*i+1] = y[i].getReal() + F[2*i-1];
257 }
258
259 return F;
260 }
261 }