From 61290b4c45a83dd1615bcd475b0f6bb00d747b71 Mon Sep 17 00:00:00 2001 From: Gianpaolo Coro Date: Tue, 30 Apr 2013 14:14:18 +0000 Subject: [PATCH] git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-analysis/EcologicalEngine@74266 82a268e6-3cf1-43bd-a215-b396298e98cf --- .../dataanalysis/ecoengine/signals/Delta.java | 38 +++ .../ecoengine/signals/SignalConversions.java | 273 ++++++++++++++++ .../ecoengine/signals/SignalProcessing.java | 300 ++++++++++++++++++ 3 files changed, 611 insertions(+) create mode 100644 src/main/java/org/gcube/dataanalysis/ecoengine/signals/Delta.java create mode 100644 src/main/java/org/gcube/dataanalysis/ecoengine/signals/SignalConversions.java create mode 100644 src/main/java/org/gcube/dataanalysis/ecoengine/signals/SignalProcessing.java diff --git a/src/main/java/org/gcube/dataanalysis/ecoengine/signals/Delta.java b/src/main/java/org/gcube/dataanalysis/ecoengine/signals/Delta.java new file mode 100644 index 0000000..5a59ea5 --- /dev/null +++ b/src/main/java/org/gcube/dataanalysis/ecoengine/signals/Delta.java @@ -0,0 +1,38 @@ +package org.gcube.dataanalysis.ecoengine.signals; + +public class Delta { + + public static void calcDelta(double A[][], int numCoeff) throws Exception { + int delta; + + for (int j = 0; j < numCoeff; j++) { + delta = j + numCoeff; + completeDelta(A, j, delta); + } + } + + public static void calcDoubleDelta(double A[][], int numCoeff) throws Exception { + int fine = numCoeff * 2; + for (int delta = numCoeff; delta < fine; delta++) { + int doppioDelta = delta + numCoeff; + completeDelta(A, delta, doppioDelta); + } + } + + private static void completeDelta(double A[][], int j, int d) throws Exception { + if (A.length < 4) { + throw new Exception(); + } + if (A.length > 2) { + A[0][d] = A[1][j] - A[0][j]; + A[1][d] = (A[2][j] - A[0][j]) - (A[0][j] - A[1][j]) / 4; + } + for (int i = 2; i < A.length - 2; i++) + A[i][d] = ((2 * (A[i + 2][j] - A[i - 2][j])) + (A[i + 1][j] - A[i - 1][j])) / 8; + if (A.length > 3) { + A[A.length - 2][d] = (A[A.length - 1][j] - A[A.length - 3][j]) - (A[A.length - 1][j] - A[A.length - 2][j]); + A[A.length - 1][d] = A[A.length - 2][j] - A[A.length - 1][j]; + } + } + +} diff --git a/src/main/java/org/gcube/dataanalysis/ecoengine/signals/SignalConversions.java b/src/main/java/org/gcube/dataanalysis/ecoengine/signals/SignalConversions.java new file mode 100644 index 0000000..86b91ca --- /dev/null +++ b/src/main/java/org/gcube/dataanalysis/ecoengine/signals/SignalConversions.java @@ -0,0 +1,273 @@ +package org.gcube.dataanalysis.ecoengine.signals; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.Arrays; + +import javax.swing.JPanel; + +import marytts.signalproc.display.SpectrogramCustom; +import marytts.signalproc.window.Window; + +import com.rapidminer.example.Attribute; +import com.rapidminer.example.Example; +import com.rapidminer.example.ExampleSet; +import com.rapidminer.example.table.MemoryExampleTable; + +/** + * includes tools for basic signal transformations: + * delta + double delta + * center frequency + * cepstral coefficients calculation + * spectrum frequency cut + * transformation to and from Rapid Miner Example Set + * filterbanks + * fequency to mel + * frequency to index in fft + * sinusoid signal generation + * inverse mel + * log10 + * mel filterbanks + * sample to time and time to sample + * signal timeline generation + * index to time in spectrogram + * spectrogram calculation and display + * time to index in spectrogram + * + * @author coro + * + */ +public class SignalConversions { + + public static double[][] addDeltaDouble(double[][] features) throws Exception{ + int vectorL = features[0].length; + double[][] delta = new double[features.length][features[0].length*3]; + + for (int k=0;k"+signal[i]); + for (Attribute a : e.getAttributes()) { + rebuiltSignal[id] = e.getValue(a); + } + } + } + + public static int[] fftBinIndices(double samplingRate, int frameSize, int numMelFilters, int numFequencies, float lowerFilterFreq, float upperFilterFreq) { + int cbin[] = new int[numFequencies+2]; + System.out.println("New Filter banks: "+numFequencies); + cbin[0] = (int) Math.round(lowerFilterFreq / samplingRate * frameSize); + cbin[cbin.length - 1] = frequencyIndex(upperFilterFreq, frameSize, (float)samplingRate); + System.out.println("F0: "+lowerFilterFreq); + for (int i = 1; i <= numFequencies; i++) { + double fc = centerFreq(i, samplingRate, lowerFilterFreq, numMelFilters); + System.out.println("F"+(i)+": "+fc); + cbin[i] = (int) Math.round(fc / samplingRate * frameSize); + } + + System.out.println("F"+(cbin.length - 1)+": "+upperFilterFreq); + + return cbin; + } + + public static int[] fftBinIndices(double samplingRate, int frameSize, int numMelFilters, float lowerFilterFreq) { + int cbin[] = new int[numMelFilters + 2]; + + cbin[0] = (int) Math.round(lowerFilterFreq / samplingRate * frameSize); + cbin[cbin.length - 1] = (int) (frameSize / 2); + + for (int i = 1; i <= numMelFilters; i++) { + double fc = centerFreq(i, samplingRate, lowerFilterFreq, numMelFilters); + + cbin[i] = (int) Math.round(fc / samplingRate * frameSize); + } + + return cbin; + } + + public static double freqToMel(double freq) { + return 2595 * log10(1 + freq / 700); + } + + + public static int frequencyIndex(float frequency, int fftSize, float samplingRate) { + return Math.round(frequency * fftSize / samplingRate); + } + + static double[] generateSinSignal(int signalLength, float timeShift, float frequency) { + //final float frequency = 0.3f;// 1f; + + double samples[] = new double[signalLength]; + float time = 0; + for (int i = 0; i < samples.length; i++) { + samples[i] = (float) Math.sin(2f * Math.PI * frequency * time); + // time += 1f / (float) samplingRate; + time += timeShift; + } + return samples; + } + + private static double inverseMel(double x) { + double temp = Math.pow(10, x / 2595) - 1; + return 700 * (temp); + } + + + public static double log10(double value) { + return Math.log(value) / Math.log(10); + } + + public static double[] melFilter(double bin[], int cbin[], int numMelFilters) { + double temp[] = new double[numMelFilters + 2]; + + for (int k = 1; k <= numMelFilters; k++) { + double num1 = 0, num2 = 0; + + for (int i = cbin[k - 1]; i <= cbin[k]; i++) { + num1 += ((i - cbin[k - 1] + 1) / (cbin[k] - cbin[k - 1] + 1)) * bin[i]; + } + + for (int i = cbin[k] + 1; i <= cbin[k + 1]; i++) { + num2 += (1 - ((i - cbin[k]) / (cbin[k + 1] - cbin[k] + 1))) * bin[i]; + } + + temp[k] = num1 + num2; + } + + double fbank[] = new double[numMelFilters]; + for (int i = 0; i < numMelFilters; i++) { + fbank[i] = temp[i + 1]; + } + + return fbank; + } + + public static int recalculateMaxMelFilters(double samplingRate, int numMelFilters, float lowerFilterFreq, float maxFilterFreq){ + int bestIndex=1; + for (int i = 1; i <= numMelFilters; i++) { + double fc = centerFreq(i, samplingRate, lowerFilterFreq, numMelFilters); + System.out.println("fc "+fc); + if (fc>maxFilterFreq){ + bestIndex=i; + break; + } + } + + return bestIndex-1; + } + + public static double sample2Time(int sample, int sampleRate) { + return (double) sample / (double) sampleRate; + } + + public static double[] signalTimeLine(int signalLength, double samplingRate) { + double time[] = new double[signalLength]; + Arrays.fill(time, Double.NaN); + + for (int i = 0; i < signalLength; i++) { + time[i] = (double) i / (double) samplingRate; + } + System.out.println("time " + time[signalLength - 1] * samplingRate + " vs " + signalLength); + return time; + } + + public static float spectrumTime(float linearTime, float windowShiftTime) { + return linearTime / windowShiftTime; + } + + public static double[][] spectrogram(String name, double[] signal, int samplingRate, int windowshift, int frameslength, boolean display) throws Exception { + SpectrogramCustom spec = new SpectrogramCustom(signal, samplingRate, Window.get(Window.HAMMING, frameslength), windowshift, frameslength, 640, 480); + double[][] spectrum = spec.spectra.toArray(new double[spec.spectra.size()][]); + if (display) { + spec.showInJFrame(name, true, true); + /* + * save spectrograms to files BufferedImage image = + * createImage(spec); + * ImageIO.write(ImageTools.toBufferedImage(image), "png", new + * File(name+".png")); + */ + // Thread.sleep(2000); + } + return spectrum; + } + + public static float spectrumTimeFromIndex(int index, float windowShiftTime) { + return index * windowShiftTime; + } + + public static int spectrumIndex(float linearTime, float windowShiftTime) { + return (int) (linearTime / windowShiftTime); + } + + public static int time2Sample(double time, int sampleRate) { + return (int) (time * sampleRate); + } + +} diff --git a/src/main/java/org/gcube/dataanalysis/ecoengine/signals/SignalProcessing.java b/src/main/java/org/gcube/dataanalysis/ecoengine/signals/SignalProcessing.java new file mode 100644 index 0000000..bf0b887 --- /dev/null +++ b/src/main/java/org/gcube/dataanalysis/ecoengine/signals/SignalProcessing.java @@ -0,0 +1,300 @@ +package org.gcube.dataanalysis.ecoengine.signals; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.gcube.contentmanagement.graphtools.data.BigSamplesTable; +import org.gcube.contentmanagement.graphtools.plotting.graphs.NumericSeriesGraph; +import org.gcube.contentmanagement.graphtools.plotting.graphs.TimeSeriesGraph; +import org.gcube.contentmanagement.lexicalmatcher.utils.MathFunctions; +import org.jfree.data.time.FixedMillisecond; +import org.jfree.data.time.TimeSeriesCollection; +import org.jfree.data.xy.XYSeriesCollection; + +import com.rapidminer.RapidMiner; +import com.rapidminer.example.ExampleSet; +import com.rapidminer.operator.preprocessing.sampling.AbsoluteSampling; +import com.rapidminer.operator.preprocessing.series.filter.SeriesMissingValueReplenishment; +import com.rapidminer.tools.OperatorService; + +public class SignalProcessing { + + public static double[][] applyFilterBank(double[][] feature, int numCepstra, int numMelFilters, int samplingRate, int frameLength, float minCutFequency, float maxCutFrequency) throws Exception { + // recalculate Mel filters on the basis of the maxFrequency + int recalcMelFilters = SignalConversions.recalculateMaxMelFilters(samplingRate, numMelFilters, minCutFequency, maxCutFrequency); + + double[][] mels = new double[feature.length][numCepstra]; + int i = 0; + for (double[] bin : feature) { + int cbin[] = SignalConversions.fftBinIndices(samplingRate, frameLength, numMelFilters, recalcMelFilters, minCutFequency, maxCutFrequency); + double f[] = SignalConversions.melFilter(bin, cbin, recalcMelFilters); + double cepstra[] = SignalConversions.cepCoefficients(f, numCepstra, recalcMelFilters); + mels[i] = cepstra; + i++; + } + + double[][] deltamels = new double[feature.length][numCepstra * 3]; + for (int k = 0; k < feature.length; k++) { + for (int g = 0; g < mels[0].length; g++) { + deltamels[k][g] = mels[k][g]; + } + } + + Delta.calcDelta(deltamels, numCepstra); + Delta.calcDoubleDelta(deltamels, numCepstra); + + return deltamels; + } + + public static double[][] calculateSumSpectrum(List signals, int windowShiftSamples, int frameLength, int samplingRate) throws Exception { + + int signalLenght = signals.get(0).length; + System.out.println("TRIALS LENGHT " + signalLenght); + + List spectrograms = new ArrayList(); + System.out.println("Getting Spectra"); + int j = 0; + // get all spectrograms + for (double[] signal : signals) { + double[][] spectro = SignalConversions.spectrogram("Spectrogram", signal, samplingRate, windowShiftSamples, frameLength, false); + System.out.println("Signal Number " + (j + 1) + " spectrum lenght " + ((spectro.length * windowShiftSamples) / samplingRate)); + spectrograms.add(spectro); + j++; + } + + System.out.println("Summing Spectra"); + // sum all spectrograms + double[][] sumSpectro = SignalProcessing.sumSpectra(spectrograms); + spectrograms = null; + + return sumSpectro; + + } + + // concatenates several spectra + public static double[][] concatenateSpectra(List spectra) { + double[][] firstSpectrum = spectra.get(0); + int mi = firstSpectrum.length; + int mj = firstSpectrum[0].length; + int nSpectra = spectra.size(); + double[][] concatenatedSpectrum = new double[mi][mj * nSpectra]; + int k = 0; + + for (double[][] spectrum : spectra) { + + for (int i = 0; i < mi; i++) { + for (int j = 0; j < mj; j++) + concatenatedSpectrum[i][j + (k * mj)] = spectrum[i][j]; + } + k++; + } + + return concatenatedSpectrum; + } + + public static void displaySignalWithGenericTime(double[] signal, float t0, float timeshift, String name) { + org.jfree.data.xy.XYSeries xyseries = new org.jfree.data.xy.XYSeries(name); + float time = t0; + for (int i = 0; i < signal.length; i++) { + xyseries.add(time, signal[i]); + time = time + timeshift; + } + XYSeriesCollection collection = new XYSeriesCollection(xyseries); + NumericSeriesGraph nsg = new NumericSeriesGraph(name); + nsg.render(collection); + } + + public static void displaySignalWithTime(double[] signal, Date[] dates, String name, String format) { + org.jfree.data.time.TimeSeries series = new org.jfree.data.time.TimeSeries(name); + for (int i = 0; i < signal.length; i++) + series.add(new FixedMillisecond(dates[i]), signal[i]); + + TimeSeriesCollection dataset = new TimeSeriesCollection(); + dataset.addSeries(series); + + TimeSeriesGraph tsg = new TimeSeriesGraph(name); + tsg.timeseriesformat = format; + tsg.render(dataset); + } + + public static double[] downSample(double[] signal, int numElements) throws Exception { + System.setProperty("rapidminer.init.operators", "operators.xml"); + RapidMiner.init(); + double[] rebuiltSignal = new double[signal.length]; + Arrays.fill(rebuiltSignal, Double.NaN); + BigSamplesTable samples = new BigSamplesTable(); + for (int k = 0; k < signal.length; k++) { + samples.addSampleRow("" + k, signal[k]); + } + ExampleSet es = samples.generateExampleSet(); + + System.out.println("Example Set Created"); + + AbsoluteSampling sampler = (AbsoluteSampling) OperatorService.createOperator("AbsoluteSampling"); + sampler.setParameter("sample_size", "" + numElements); + sampler.setParameter("local_random_seed", "-1"); + es = sampler.apply(es); + System.out.println("Finished"); + + SignalConversions.exampleSet2Signal(rebuiltSignal, es); + + return rebuiltSignal; + } + + public static double[][] extractSumSpectrum(String file, int windowShiftSamples, int frameLength, int samplingRate) throws Exception { + List signals = SignalProcessing.readSignalsFromCSV(file, ","); + // int numSignals = signals.size(); + int signalLenght = signals.get(0).length; + + List sumspectrograms = new ArrayList(); + + List spectrograms = new ArrayList(); + System.out.println("Getting Spectra"); + int j = 0; + // get all spectrograms + for (double[] signal : signals) { + System.out.println("Signal Number " + (j + 1)); + double[][] spectro = SignalConversions.spectrogram("Spectrogram", signal, samplingRate, windowShiftSamples, frameLength, false); + spectrograms.add(spectro); + j++; + } + + System.out.println("Summing Spectra"); + // sum all spectrograms + double[][] sumSpectro = SignalProcessing.sumSpectra(spectrograms); + spectrograms = null; + + return sumSpectro; + } + + public static Date[] fillTimeLine(double[] timeseconds, double samplingRate) throws Exception { + double[] values = new double[timeseconds.length]; + for (int i = 0; i < timeseconds.length; i++) + values[i] = timeseconds[i] * 1000d; + double[] milliseconds = fillTimeSeries(values, timeseconds, samplingRate); + Date[] dates = new Date[milliseconds.length]; + for (int i = 0; i < milliseconds.length; i++) + dates[i] = new Date((long) milliseconds[i]); + + return dates; + } + + public static double[] fillTimeSeries(double[] values, double[] timeseconds, double samplingRate) throws Exception { + System.setProperty("rapidminer.init.operators", "operators.xml"); + RapidMiner.init(); + + double t0 = timeseconds[0]; + double t1 = timeseconds[timeseconds.length - 1]; + int signalength = (int) ((t1 - t0) * samplingRate) + 1; + double signal[] = new double[signalength]; + Arrays.fill(signal, Double.NaN); + for (int i = 0; i < values.length; i++) { + if (values[i] != Double.NaN) { + int index = (int) ((timeseconds[i] - t0) * samplingRate); + signal[index] = values[i]; + } + } + double[] rebuiltSignal = new double[signal.length]; + + BigSamplesTable samples = new BigSamplesTable(); + for (int k = 0; k < signal.length; k++) { + samples.addSampleRow("" + k, signal[k]); + } + + ExampleSet es = samples.generateExampleSet(); + System.out.println("Example Set Created"); + + SeriesMissingValueReplenishment sampler = (SeriesMissingValueReplenishment) OperatorService.createOperator("SeriesMissingValueReplenishment"); + sampler.setParameter("attribute_name", "att0"); + sampler.setParameter("replacement", "3"); + es = sampler.apply(es); + System.out.println("Finished"); + + SignalConversions.exampleSet2Signal(rebuiltSignal, es); + + return rebuiltSignal; + } + + public static double[][] multiSignalAnalysis(List signals, int samplingRate, int windowshift, int frameslength, boolean display) throws Exception { + + List spectra = new ArrayList(); + + for (double[] signal : signals) + spectra.add(SignalConversions.spectrogram("Spectrogram", signal, samplingRate, windowshift, frameslength, display)); + + double[][] sumSpec = sumSpectra(spectra); + return sumSpec; + + } + + public static List readSignalsFromCSV(String file, String delimiter) throws Exception { + + BufferedReader br = new BufferedReader(new FileReader(new File(file))); + String line = br.readLine(); + List signals = new ArrayList(); + while (line != null) { + double[] signal = readSignalFromCSVLine(line, delimiter); + signals.add(signal); + line = br.readLine(); + } + + br.close(); + return signals; + } + + public static double[] readSignalFromCSVLine(String line, String delimiter) throws Exception { + String[] splitted = line.split(delimiter); + double[] signal = new double[splitted.length]; + for (int i = 0; i < splitted.length; i++) + signal[i] = Double.parseDouble(splitted[i]); + return signal; + } + + // sums several spectra of the same length + public static double[][] sumSpectra(List spectra) { + double[][] firstSpectrum = spectra.get(0); + int mi = firstSpectrum.length; + int mj = firstSpectrum[0].length; + double[][] sumSpectrum = new double[mi][mj]; + int k = 0; + for (double[][] spectrum : spectra) { + for (int i = 0; i < mi; i++) { + for (int j = 0; j < mj; j++) + sumSpectrum[i][j] = MathFunctions.incrementAvg(sumSpectrum[i][j], spectrum[i][j], k); + } + k++; + } + return sumSpectrum; + } + + public static double[][] takeCentralSpectrum(double[][] spectrum, float numOfCentralSeconds, float windowShiftTime, int sampleRate) { + + float maxTime = ((float) spectrum.length * (float) windowShiftTime); + + float centralTime = (maxTime / (2f * numOfCentralSeconds)); + + System.out.println("Max Time in the Spectrum " + maxTime + " Central time " + centralTime); + + int startIndex = (int) (centralTime / windowShiftTime); + int endIndex = (int) ((centralTime + numOfCentralSeconds) / windowShiftTime); + + System.out.println("Recalculated lenght " + maxTime + " sec"); + System.out.println("Lenght " + spectrum.length); + + System.out.println("Start " + startIndex + " End " + endIndex + " max " + spectrum.length + " Cut lenght " + (endIndex - startIndex + 1) * windowShiftTime); + + double[][] cutSpectrum = new double[endIndex - startIndex + 1][spectrum[0].length]; + + for (int i = startIndex; i <= endIndex; i++) { + cutSpectrum[i - startIndex] = spectrum[i]; + } + + return cutSpectrum; + } + +}