001: package JSci.maths.wavelet;
002:
003: import JSci.maths.*;
004: import JSci.maths.wavelet.*;
005:
006: /****************************************************
007: * This class is used to encapsulate wavelet
008: * packets coefficients.
009: * @author Daniel Lemire
010: *****************************************/
011: public final class FWTPacketCoef extends Object implements
012: NumericalConstants, Cloneable {
013: protected double[][] coefs;
014: protected boolean[] StandardChoice;
015: final static double normalisation = 1.0 / SQRT2;
016:
017: public FWTPacketCoef() {
018: }
019:
020: /**********************************************
021: ***********************************************/
022: public FWTPacketCoef(double[][] v, boolean[] b) {
023: coefs = v;
024: StandardChoice = b;
025: if (b.length != v.length - 1) {
026: throw new IllegalArgumentException(
027: "boolean[].length must be exactly double[][].length -1: boolean[].length="
028: + b.length + " and double[][].length="
029: + v.length);
030: }
031: }
032:
033: /********************************************
034: * Return a copy of this object
035: *********************************************/
036: public Object clone() {
037: try {
038: FWTPacketCoef fwtp = (FWTPacketCoef) super .clone();
039: if (coefs != null)
040: fwtp.coefs = ArrayMath.copy(coefs);
041: if (StandardChoice != null) {
042: fwtp.StandardChoice = new boolean[StandardChoice.length];
043: System.arraycopy(StandardChoice, 0,
044: fwtp.StandardChoice, 0, StandardChoice.length);
045: }
046: return (fwtp);
047: } catch (CloneNotSupportedException cnse) {
048: throw new InternalError();
049: }
050: }
051:
052: /*************************************************
053: **************************************************/
054: public int getJ() {
055: return (coefs.length);
056: }
057:
058: /*************************************************
059: **************************************************/
060: public int dimension(int i) {
061: if ((i < 0) || (i >= coefs.length)) {
062: throw new IllegalArgumentException(
063: "This scale doesn't exist : " + i + ", "
064: + coefs.length);
065: }
066: return (coefs[i].length);
067: }
068:
069: /*******************************************************
070: ********************************************************/
071: public double[][] getCoefs() {
072: return (coefs);
073: }
074:
075: /***************************
076: * Compute the L2 norm of the
077: * coefficients
078: ****************************/
079: public double[] norm() {
080: double[] ans = new double[coefs.length];
081: for (int j = 0; j < coefs.length; j++) {
082: ans[j] = ArrayMath.norm(coefs[j]);
083: }
084: return (ans);
085: }
086:
087: /***************************
088: * Compute the L2 norm of the
089: * coefficients at "scale" i.
090: ****************************/
091: public double norm(int i) {
092: if ((i < 0) || (i >= coefs.length)) {
093: throw new IllegalArgumentException("The integer parameter "
094: + i + " should be between 0 and "
095: + (coefs.length - 1));
096: }
097: double ans = ArrayMath.norm(coefs[i]);
098: return (ans);
099: }
100:
101: /************************************
102: * Compute the sum of the squares of
103: * the coefficients
104: *************************************/
105: private double[] sumSquares() {
106: double[] ans = new double[coefs.length];
107: for (int j = 0; j < coefs.length; j++) {
108: ans[j] = ArrayMath.sumSquares(coefs[j]);
109: }
110: return (ans);
111: }
112:
113: /************************************
114: * Compute the sum of the squares of
115: * the coefficients
116: *************************************/
117: public double sumSquares(int i) {
118: if ((i < 0) || (i >= coefs.length)) {
119: throw new IllegalArgumentException("The integer parameter "
120: + i + " must be between 0 et " + (coefs.length - 1));
121: }
122: double ans = ArrayMath.sumSquares(coefs[i]);
123: return (ans);
124: }
125:
126: /************************************
127: *************************************/
128: public double mass(int i) {
129: if ((i < 0) || (i >= coefs.length)) {
130: throw new IllegalArgumentException("The integer parameter "
131: + i + " should be between 0 and "
132: + (coefs.length - 1));
133: }
134: double ans = ArrayMath.mass(coefs[i]);
135: return (ans);
136: }
137:
138: /************************************
139: *************************************/
140: private double[] variance() {
141: double[] ans = new double[coefs.length];
142: for (int j = 0; j < coefs.length; j++) {
143: ans[j] = ArrayMath.variance(coefs[j]);
144: }
145: return (ans);
146: }
147:
148: /************************************
149: *************************************/
150: public double variance(int i) {
151: if ((i < 0) || (i >= coefs.length)) {
152: throw new IllegalArgumentException("The integer parameter "
153: + i + " should be between 0 and "
154: + (coefs.length - 1));
155: }
156: double ans = ArrayMath.variance(coefs[i]);
157: return (ans);
158: }
159:
160: public double sumEnergies() {
161: if (coefs.length <= 1) {
162: throw new IllegalArgumentException(
163: "No wavelet coefficients!");
164: }
165: double[] energies = sumSquares();
166: double ans = 0.0;
167: for (int k = 0; k < energies.length; k++) {
168: ans += energies[k];
169: }
170: return (ans);
171: }
172:
173: public double entropy() {
174: if (coefs.length <= 1) {
175: throw new IllegalArgumentException(
176: "No wavelet coefficients!");
177: }
178: double sumEnergies = sumEnergies();
179: int nombreDeCoefficients = 0;
180: for (int k = 0; k < coefs.length; k++) {
181: nombreDeCoefficients += coefs[k].length;
182: }
183: double[] pourcentageDEnergie = new double[nombreDeCoefficients];
184: int pos = 0;
185: for (int k = 0; k < coefs.length; k++) {
186: for (int l = 0; l < coefs[k].length; l++) {
187: pourcentageDEnergie[pos] = coefs[k][l] * coefs[k][l]
188: / sumEnergies;
189: pos++;
190: }
191: }
192: return (EngineerMath.icf(pourcentageDEnergie));
193: }
194:
195: public double sumVariance() {
196: if (coefs.length <= 1) {
197: throw new IllegalArgumentException(
198: "No wavelet coefficients!");
199: }
200: double[] variances = variance();
201: double ans = 0.0;
202: for (int k = 0; k < variances.length; k++) {
203: ans += variances[k];
204: }
205: return (ans);
206: }
207:
208: public double energyRatio(int i) {
209: if (coefs.length <= 1) {
210: throw new IllegalArgumentException(
211: "No wavelet coefficients!");
212: }
213: if ((i < 0) || (i >= coefs.length)) {
214: throw new IllegalArgumentException("The integer parameter "
215: + i + " should be between 0 and "
216: + (coefs.length - 1));
217: }
218: if (sumEnergies() == 0) {
219: if (coefs.length != 0) {
220: return (1 / coefs.length);
221: } else {
222: throw new IllegalArgumentException("No energy!");
223: }
224: }
225: return (sumSquares(i) / sumEnergies());
226: }
227:
228: public double varianceRatio(int i) {
229: if (coefs.length <= 1) {
230: throw new IllegalArgumentException(
231: "No wavelet coefficients!");
232: }
233: if ((i < 0) || (i >= coefs.length)) {
234: throw new IllegalArgumentException("The integer parament "
235: + i + " should be between 0 and "
236: + (coefs.length - 1));
237: }
238: if (sumVariance() == 0) {
239: if (coefs.length != 0) {
240: return (1 / coefs.length);
241: } else {
242: throw new IllegalArgumentException("No variance!");
243: }
244: }
245: return (variance(i) / sumVariance());
246: }
247:
248: /**
249: * Compute the Shannon entropy.
250: */
251: public double icf() {
252: if (coefs.length <= 1) {
253: throw new IllegalArgumentException(
254: "No wavelet coefficients!");
255: }
256: double[] pe = new double[coefs.length - 1];
257: for (int j = 0; j < coefs.length; j++) {
258: pe[j] = energyRatio(j);
259: }
260: return (EngineerMath.icf(pe));
261: }
262:
263: public double varianceICF() {
264: if (coefs.length <= 1) {
265: throw new IllegalArgumentException(
266: "No wavelet coefficients!");
267: }
268: double[] pv = new double[coefs.length - 1];
269: for (int j = 0; j < coefs.length; j++) {
270: pv[j] = varianceRatio(j);
271: }
272: return (EngineerMath.icf(pv));
273: }
274:
275: public void setCoefs(double[][] v) {
276: coefs = v;
277: }
278:
279: /***************************
280: * Allows the user to set
281: * the Wavelet Packet chosen
282: ****************************/
283: public void setPacket(boolean[] b) {
284: StandardChoice = b;
285: }
286:
287: public void setCoefs(double[] v, int i) {
288: if ((i < 0) || (i >= coefs.length)) {
289: throw new IllegalArgumentException("The integer parameter "
290: + i + " should be between 0 and "
291: + (coefs.length - 1));
292: }
293: coefs[i] = v;
294: }
295:
296: public void synthesize(Filter filtreprimaire, double[] param) {
297: if (coefs.length <= 1) {
298: throw new IllegalArgumentException(
299: "No synthesis left to do: " + coefs.length);
300: }
301: double[] V0, W0;
302: if (StandardChoice[StandardChoice.length - 1]) {
303: V0 = filtreprimaire.lowpass(coefs[coefs.length - 1], param);
304: // Lowpass filters must be renormalized.
305: V0 = ArrayMath.scalarMultiply(normalisation, V0);
306: W0 = filtreprimaire
307: .highpass(coefs[coefs.length - 2], param);
308: } else {
309: V0 = filtreprimaire.lowpass(coefs[coefs.length - 2], param);
310: // Lowpass filters must be renormalized.
311: V0 = ArrayMath.scalarMultiply(normalisation, V0);
312: W0 = filtreprimaire
313: .highpass(coefs[coefs.length - 1], param);
314: }
315: if (V0.length != W0.length) {
316: throw new IllegalArgumentException(
317: "Synthesis is impossible : bad data/multiresolution? "
318: + coefs[0].length + ", "
319: + coefs[coefs.length - 1].length + ", "
320: + V0.length + ", " + W0.length);
321: }
322: V0 = ArrayMath.add(V0, W0);
323: double[][] c = new double[coefs.length - 1][];
324: for (int j = 0; j < coefs.length - 2; j++) {
325: c[j] = coefs[j];
326: }
327: c[coefs.length - 1] = V0;
328: coefs = c;
329: boolean[] b = new boolean[c.length - 1];
330: for (int j = 0; j < b.length; j++) {
331: b[j] = StandardChoice[j];
332: }
333: StandardChoice = b;
334: }
335:
336: public void synthesize(Filter filtreprimaire, double[] param,
337: int jmax) {
338: if ((jmax < 0) || (jmax > coefs.length - 1)) {
339: throw new IllegalArgumentException("The integer parameter "
340: + jmax + " must be between 0 and "
341: + (coefs.length - 1));
342: }
343: for (int j = 0; j < jmax; j++) {
344: synthesize(filtreprimaire, param);
345: }
346: }
347:
348: public void synthesizeTout(Filter filtreprimaire, double[] param) {
349: synthesize(filtreprimaire, param, coefs.length - 1);
350: }
351:
352: public void synthesize(Filter filtreprimaire) {
353: if (coefs.length <= 1) {
354: throw new IllegalArgumentException(
355: "No synthesis left to do: " + coefs.length);
356: }
357: double[] V0, W0;
358: if (StandardChoice[StandardChoice.length - 1]) {
359: V0 = filtreprimaire.lowpass(coefs[coefs.length - 1]);
360: // Lowpass filters must be renormalized.
361: V0 = ArrayMath.scalarMultiply(normalisation, V0);
362: W0 = filtreprimaire.highpass(coefs[coefs.length - 2]);
363: } else {
364: V0 = filtreprimaire.lowpass(coefs[coefs.length - 2]);
365: // Lowpass filters must be renormalized.
366: V0 = ArrayMath.scalarMultiply(normalisation, V0);
367: W0 = filtreprimaire.highpass(coefs[coefs.length - 1]);
368: }
369: if (V0.length != W0.length) {
370: throw new IllegalArgumentException(
371: "Synthesis is impossible : bad data/multiresolution? "
372: + coefs[0].length + ", "
373: + coefs[coefs.length - 1].length + ", "
374: + V0.length + ", " + W0.length);
375: }
376: V0 = ArrayMath.add(V0, W0);
377: double[][] c = new double[coefs.length - 1][];
378: for (int j = 0; j < coefs.length - 2; j++) {
379: c[j] = coefs[j];
380: }
381: c[coefs.length - 1] = V0;
382: coefs = c;
383: boolean[] b = new boolean[c.length - 1];
384: for (int j = 0; j < b.length; j++) {
385: b[j] = StandardChoice[j];
386: }
387: StandardChoice = b;
388: }
389:
390: public void synthesize(Filter filtreprimaire, int jmax) {
391: if ((jmax < 0) || (jmax > coefs.length - 1)) {
392: throw new IllegalArgumentException("The integer parameter "
393: + jmax + " must be between 0 and "
394: + (coefs.length - 1));
395: }
396: for (int j = 0; j < jmax; j++) {
397: synthesize(filtreprimaire);
398: }
399: }
400:
401: public void synthesizeAll(Filter filtreprimaire) {
402: synthesize(filtreprimaire, coefs.length - 1);
403: }
404:
405: public Signal rebuildSignal(Filter filtreprimaire) {
406: FWTCoef fwt = new FWTCoef(coefs);// copie
407: fwt.synthesizeAll(filtreprimaire);
408: return (new Signal(fwt.getCoefs()[0]));
409: }
410:
411: public Signal rebuildSignal(Filter filtreprimaire, double[] param) {
412: FWTCoef fwt = new FWTCoef(coefs);// copie
413: fwt.synthesizeAll(filtreprimaire, param);
414: return (new Signal(fwt.getCoefs()[0]));
415: }
416:
417: /*********************************************
418: * Denoises by zero-ing any value above a given percentile cut-off.
419: * @param p percentile cut-off, must be between 0 and 1.
420: **********************************************/
421: public void denoise(double p) {
422: for (int k = 1; k < coefs.length; k++) {
423: coefs[k] = denoise(coefs[k], p);
424: }
425: }
426:
427: /*********************************************
428: * Denoises by zero-ing any value above a given percentile cut-off.
429: * @param p percentile cut-off, must be between 0 and 1.
430: * @param k the index of the coefficient array to denoise.
431: **********************************************/
432: public void denoise(double p, int k) {
433: coefs[k] = denoise(coefs[k], p);
434: }
435:
436: /**************************************
437: * Denoises by zero-ing any value above a given percentile cut-off.
438: * @param v an array to denoise.
439: * @param p percentile cut-off, must be between 0 and 1.
440: ***************************************/
441: public static double[] denoise(double[] v, double p) {
442: if (p == 0.0)
443: return (v);
444: double[] ans = v;
445: double seuil = ArrayMath.percentile(ArrayMath.abs(ans), 1 - p);
446: for (int k = 0; k < ans.length; k++) {
447: if (Math.abs(ans[k]) >= seuil) {
448: ans[k] = 0.0;
449: }
450: }
451: return (ans);
452: }
453:
454: /*********************************************
455: * Compresses by zero-ing any value below a given percentile cut-off.
456: * @param p percentile cut-off, must be between 0 and 1.
457: **********************************************/
458: public void compress(double p) {
459: for (int k = 0; k < coefs.length; k++) {
460: coefs[k] = compress(coefs[k], p);
461: }
462: }
463:
464: /*********************************************
465: * Compresses by zero-ing any value below a given percentile cut-off.
466: * @param p percentile cut-off, must be between 0 and 1.
467: * @param k the index of the coefficient array to compress.
468: **********************************************/
469: public void compress(double p, int k) {
470: coefs[k] = compress(coefs[k], p);
471: }
472:
473: /**************************************
474: * Compresses by zero-ing any value below a given percentile cut-off.
475: * @param v an array to compress.
476: * @param p percentile cut-off, must be between 0 and 1.
477: ***************************************/
478: public static double[] compress(double[] v, double p) {
479: if (p == 0.0)
480: return (v);
481: double[] ans = v;
482: double seuil = ArrayMath.percentile(ArrayMath.abs(ans), p);
483: for (int k = 0; k < ans.length; k++) {
484: if (Math.abs(ans[k]) <= seuil) {
485: ans[k] = 0.0;
486: }
487: }
488: return (ans);
489: }
490:
491: /*********************************************
492: * Denoises by zero-ing any value above a given cut-off.
493: * @param p cut-off.
494: **********************************************/
495: public void denoiseHard(double p) {
496: for (int k = 0; k < coefs.length; k++) {
497: coefs[k] = denoiseHard(coefs[k], p);
498: }
499: }
500:
501: /*********************************************
502: * Denoises by zero-ing any value above a given cut-off.
503: * @param p cut-off.
504: * @param k the index of the coefficient array to denoise.
505: **********************************************/
506: public void denoiseHard(double p, int k) {
507: coefs[k] = denoiseHard(coefs[k], p);
508: }
509:
510: /**************************************
511: * Denoises by zero-ing any value above a given cut-off.
512: * @param v an array to denoise.
513: * @param seuil cut-off/threshold.
514: ***************************************/
515: public static double[] denoiseHard(double[] v, double seuil) {
516: if (seuil < 0.0) {
517: throw new IllegalArgumentException(
518: "The cutoff value must be positive.");
519: }
520: double[] ans = v;
521: for (int k = 0; k < ans.length; k++) {
522: if (Math.abs(ans[k]) >= seuil) {
523: ans[k] = 0.0;
524: }
525: }
526: return (ans);
527: }
528:
529: /*********************************************
530: * Compresses by zero-ing any value below a given cut-off.
531: * @param p cut-off.
532: **********************************************/
533: public void compressHard(double p) {
534: for (int k = 0; k < coefs.length; k++) {
535: coefs[k] = compressHard(coefs[k], p);
536: }
537: }
538:
539: /*********************************************
540: * Compresses by zero-ing any value below a given cut-off.
541: * @param p cut-off.
542: * @param k the index of the coefficient array to compress.
543: **********************************************/
544: public void compressHard(double p, int k) {
545: coefs[k] = compressHard(coefs[k], p);
546: }
547:
548: /**************************************
549: * Compresses by zero-ing any value below a given cut-off.
550: * @param v an array to compress.
551: * @param seuil cut-off/threshold.
552: ***************************************/
553: public static double[] compressHard(double[] v, double seuil) {
554: if (seuil < 0.0) {
555: throw new IllegalArgumentException(
556: "The cutoff value must be positive.");
557: }
558: double[] ans = v;
559: for (int k = 0; k < ans.length; k++) {
560: if (Math.abs(ans[k]) <= seuil) {
561: ans[k] = 0.0;
562: }
563: }
564: return (ans);
565: }
566: }
|