/**
*
*/
package systole.processor;
import java.math.BigDecimal;
import systole.domain.analysis.results.AnalysisResult;
import systole.domain.analysis.results.ParameterAOD;
import systole.domain.analysis.results.ParameterAOS;
import systole.domain.analysis.results.ParameterCoord;
import systole.domain.analysis.results.ParameterIAR;
import systole.domain.analysis.results.ParameterT;
import systole.domain.signals.FinalSignal;
import systole.domain.signals.Segment;
/**
* Class to calculate final parameters
*
* @author jmj
*
*
*/
public class SignalAnalyzer {
private static final BigDecimal FIFTY = new BigDecimal(50);
private static final int BEGIN_OF_WINDOW_TIME_FOR_DIASTOLE = 20;
private static final int END_OF_WINDOW_TIME_FOR_DIASTOLE = 40;
private int posOfMax;
private int posBeginigDiastole;
private int posOfIAR;
private float heartRate;
private BigDecimal k;
private FinalSignal finalSignal;
/**
*
* @param frequency
* @param finalSignal
* @param heartRate
*/
public SignalAnalyzer(BigDecimal frequency, FinalSignal finalSignal, float heartRate) {
super();
this.finalSignal = finalSignal;
this.calculatePoints();
//Período de muestreo
this.k = frequency;
this.heartRate = heartRate;
}
private void calculatePoints() {
// obtain max value, must be value 100, index 50
this.posOfMax = this.finalSignal.getFinalSegment().getPosOfMax(); //Obtiene el valor en X del maximo
this.posBeginigDiastole = this.posOfMax + BEGIN_OF_WINDOW_TIME_FOR_DIASTOLE
+ this.finalSignal.getSecondDerivative().getPosOfMax(this.posOfMax + BEGIN_OF_WINDOW_TIME_FOR_DIASTOLE, this.posOfMax + END_OF_WINDOW_TIME_FOR_DIASTOLE);
}
private int obtainIntersection(Segment firstSegment, Segment SecondSegment, int init) {
int intersection = init;
Segment majorSegment;
Segment minorSegment;
if ((init >= firstSegment.size()) || (init >= SecondSegment.size())) {
return init;
}
if ((firstSegment.elementAt(init).doubleValue()) > (SecondSegment.elementAt(init).doubleValue())) {
majorSegment = firstSegment;
minorSegment = SecondSegment;
} else {
minorSegment = firstSegment;
majorSegment = SecondSegment;
}
while (((majorSegment.size() > intersection) && (minorSegment.size() > intersection)) && (majorSegment.elementAt(intersection).doubleValue() > minorSegment.elementAt(intersection).doubleValue())) {
intersection++;
}
return intersection;
}
@SuppressWarnings("unused")
private int obtainIntersectionDownTo(Segment firstSegment, Segment SecondSegment, int endPos) {
int intersection = endPos;
Segment majorSegment;
Segment minorSegment;
if ((endPos >= firstSegment.size()) || (endPos >= SecondSegment.size())) {
return endPos;
}
if ((firstSegment.elementAt(endPos).doubleValue()) > (SecondSegment.elementAt(endPos).doubleValue())) {
majorSegment = firstSegment;
minorSegment = SecondSegment;
} else {
minorSegment = firstSegment;
majorSegment = SecondSegment;
}
while (((majorSegment.size() > intersection) && (minorSegment.size() > intersection)) && (majorSegment.elementAt(intersection).doubleValue() > minorSegment.elementAt(intersection).doubleValue())) {
intersection--;
}
return intersection;
}
private ParameterIAR calculateIAR() {
//int posOfMaxFirstDerivative = this.firsDerivatite.getPosOfMax(this.posOfMax, this.posBeginigDiastole);//Coordenada en X del maximo derivada 1
int posOfMaxFirstDerivative = this.finalSignal.getSecondDerivative().getPosOfMin(this.posOfMax, this.posBeginigDiastole);
ParameterIAR param = new ParameterIAR();
//param.setInitPos(0f);
// if distance is zero, search from other postion
if (posOfMaxFirstDerivative == 0) {
int half = (this.posBeginigDiastole - this.posOfMax) / 2;
posOfMaxFirstDerivative = half + this.finalSignal.getSecondDerivative().getPosOfMin(this.posOfMax + half, this.posBeginigDiastole);
}
posOfMaxFirstDerivative += this.posOfMax;
posOfMaxFirstDerivative = this.posOfMax + this.finalSignal.getFourthDerivative().looksFirstPositionOfNearestValueOnSubSegmentDowTo(FIFTY, posOfMax, posOfMaxFirstDerivative);
// previo a la linea superiro 30/11/11
// posOfMaxFirstDerivative = this.obtainIntersectionDownTo(this.finalSignal.getSecondDerivative(), this.finalSignal.getFourthDerivative(), posOfMaxFirstDerivative);
param.setInitPos(new ParameterCoord(this.k.multiply(new BigDecimal(posOfMaxFirstDerivative)), BigDecimal.ZERO));
param.setEndPos(new ParameterCoord(this.k.multiply(new BigDecimal(posOfMaxFirstDerivative)), this.finalSignal.getFinalSegment().elementAt(posOfMaxFirstDerivative)));
//param.setEndPos(new Float(this.posOfMax + posOfMaxFirstDerivative));
this.posOfIAR = posOfMaxFirstDerivative;
return (param);
}
private ParameterAOD calculateAOD() {
// obtengo la intersección de las derivadas para limitar la sección donde buscar el minimo
int posOfIntersection = this.obtainIntersection(this.finalSignal.getFirstDerivatite(), this.finalSignal.getSecondDerivative(), this.posBeginigDiastole);
// obtengo el minimo entre el inicio de la diastole y el cruce de la priemra y segunda derivada
int firstMinInDiastole = this.finalSignal.getFinalSegment().getPosOfMin(this.posBeginigDiastole, posOfIntersection);
// obtengo el siguiente cruce para limitar hasta donde puedo bscar el maximo
int secondIntersection = this.obtainIntersection(this.finalSignal.getFirstDerivatite(), this.finalSignal.getSecondDerivative(), posOfIntersection + 1);
// buco el maximo entre las dos intersecciones
int posOfMaxInDiastole = this.finalSignal.getFinalSegment().getPosOfMax(posOfIntersection, secondIntersection);
// llevo todo a posiciones reales
posOfMaxInDiastole += posOfIntersection + 1;
firstMinInDiastole += this.posBeginigDiastole;
// si es negativa puede ser que queden muy pegadas siendo malo el calculo
// entonces corrige
if ((this.finalSignal.getFinalSegment().get(firstMinInDiastole).floatValue() > this.finalSignal.getFinalSegment().get(posOfMaxInDiastole).floatValue()) && ((posOfMaxInDiastole - firstMinInDiastole) < 10)) {
firstMinInDiastole = this.posBeginigDiastole + ((posOfIntersection - this.posBeginigDiastole) / 2);
posOfMaxInDiastole = posOfIntersection + 1 + this.finalSignal.getSecondDerivative().getPosOfMin(posOfIntersection, this.posOfMax + END_OF_WINDOW_TIME_FOR_DIASTOLE);
}
ParameterAOD param = new ParameterAOD();
this.posBeginigDiastole = firstMinInDiastole;
param.setInitPos(new ParameterCoord(this.k.multiply(new BigDecimal(firstMinInDiastole)), this.finalSignal.getFinalSegment().get(firstMinInDiastole)));
param.setEndPos(new ParameterCoord(this.k.multiply(new BigDecimal(posOfMaxInDiastole)), this.finalSignal.getFinalSegment().get(posOfMaxInDiastole)));
return (param);
}
/**
* Calculate AOS at 50%
*
* @return longitud of OS at 50%
*/
private ParameterAOS calculateAOS() {
Integer posOfFirstFifty = this.finalSignal.getFinalSegment().looksPositionOfNearestValueOnSubSegment(SignalAnalyzer.FIFTY, 0, this.posOfMax);
Integer posOfNextFifty = this.posOfMax + this.finalSignal.getFinalSegment().
looksFirstPositionOfNearestValueOnSubSegment(SignalAnalyzer.FIFTY, this.posOfMax, this.finalSignal.getFinalSegment().size() - 2);
if (posOfNextFifty > this.posBeginigDiastole) {
posOfNextFifty = this.doExponential();
}
//Multiplico por el periodo de muestreo para que me escale de "muestras" a "milisegundos"
BigDecimal xPos = this.k.multiply(new BigDecimal(posOfFirstFifty));
BigDecimal yPos = this.k.multiply(new BigDecimal(posOfNextFifty));
ParameterAOS param = new ParameterAOS();
param.setInitPos(new ParameterCoord(xPos, SignalAnalyzer.FIFTY));
param.setEndPos(new ParameterCoord(yPos, SignalAnalyzer.FIFTY));
return (param);
}
/**
*
*
* @return time between OS and RS
*/
private ParameterT calculateT() {
ParameterT param = new ParameterT();
// primer punto, toma el máximo (sistole)
param.setInitPos(new ParameterCoord(this.k.multiply(new BigDecimal(this.posOfMax)), this.finalSignal.getFinalSegment().elementAt(this.posOfMax)));
// segundo punto, toma el maximo de la segunda derivada entre la sistole y el RS
int lastPoint = this.posOfMax + this.finalSignal.getSecondDerivative().getPosOfMax(this.posOfMax, this.posOfIAR);
param.setEndPos(new ParameterCoord(this.k.multiply(new BigDecimal(lastPoint)), this.finalSignal.getFinalSegment().elementAt(lastPoint)));
return (param);
}
private int doExponential() {
int pos = this.posOfMax + ((this.posBeginigDiastole - this.posOfMax) / 2);
boolean lower = false;
double value;
double exp;
while ((pos < this.finalSignal.getFinalSegment().size()) && (!lower)) {
value = (this.finalSignal.getFinalSegment().get(pos).doubleValue() * 2.7f);
exp = ((this.posOfIAR - pos) / 21.0f) * (-1.0f);
value = Math.pow(value, exp);
lower = value >= FIFTY.doubleValue();
pos += (lower ? 0 : 1);
}
// e_n(xi,yi) = si n < xi => P_n sino (yi*2,7)^(-(n-xi) / 25)
System.out.println("Uso la exp");
return pos;
}
/**
* @return Analysis result
*/
public AnalysisResult calculateParameters() {
AnalysisResult result = new AnalysisResult();
result.setAod(this.calculateAOD());
result.setIar(this.calculateIAR());
result.setAos(this.calculateAOS());
result.setT(this.calculateT());
result.setHeartRate((this.heartRate > 0) ? ((60 * 1000) / (this.heartRate * this.k.floatValue())) : 0f);
return result;
}
}