class HeartUtils {
private var lastMaxPos = 0
private var running = true
private var index =0
private var maxPos = 0
private var maxValue = 0f
fun init(index:Int,value:Float):Boolean{
if(maxValue<value){
maxPos = index
maxValue = value
return true
}
return false
}
private val size = 128
private val sizeX = 127
/**
* 原始数据
*/
private val src = FloatArray(size)
/**
* 平滑之后的数据
*/
private val base = FloatArray(size)
private val arg16 = FloatArray(size)
private val sub = FloatArray(size)
private val subtractsAbs = FloatArray(size)
private val line = FloatArray(size)
private var bIndex = 0;
private var argIndex = size-16
private var nowIndex = 64
private val sm32 = Smooth16()
private val sm16= Smooth16()
private val xmf = CMidXFilter()
private val rf = CMidRFilter()
private val lf = CMidLFilter()
private var flag = 0
private var rrDis=0;
fun heart():Int{
if(rrDis!=0) {
return (60 * 250f.div(rrDis)).roundToInt()
}else{
return 0
}
}
fun init(v:Float){
val a = initData(v)
val x = sm16.init(a)
arg16[argIndex]=x
if(++argIndex==size)argIndex=0
if(++nowIndex==size)nowIndex=0
index++
if(running){
init(index,subtractsAbs[nowIndex])
}
if(line[nowIndex]<subtractsAbs[nowIndex]){//大于阈值
running = true
flag=30
return
}else if(flag==0){
if(line[getI(30)]<subtractsAbs[getI(30)]){
running=true
flag = -30
return
}
}else{
if(flag<0)flag++
else flag--
return
}
if(running) {
running = false
if(lastMaxPos!=0){
var rr = maxPos-lastMaxPos
rrDis= (rf.init(rr))
// LogUtils.d("hreat = "+heart())
}
maxValue=0f
lastMaxPos=maxPos
}
}
private fun getA():Float{
return ((sub[nowIndex] *8) +sub[getI(-1)]+sub[getI(1)]+sub[getI(-2)]+sub[getI(2)]).div(12)
}
private fun getB(tag:Int = 0):Float{
val t = if(tag<0) 30+tag else tag
return (t*getA()+ (30-t)*arg16[nowIndex]).div(30)
}
private fun initData(v:Float):Float{
val b=sm32.init(v)
val s=sm32.v()
val m = s-b
val n = abs(m)
val l = xmf.init(n)
sub[bIndex]=m
line[bIndex]=l
base[bIndex]=b
src[bIndex]=s
subtractsAbs[bIndex]=n
if(++bIndex==size)bIndex=0
return m
}
private fun getI(v:Int):Int=((nowIndex+v+size).and(sizeX))
internal class Smooth16 {
private var index = 0
private val data=FloatArray(15)
private var sum = 0f
fun init(v:Float):Float{
sum-=data[index]
sum+=v
data[index++]=v
if(index==15)index=0
return sum.div(15)
}
fun v():Float{
return data[(index+7) % 15]
}
}
internal
class CMidLFilter(private val SIZE:Int=5) {
private var medIndex=2
private var index = 0
private val data=IntArray(SIZE)
private val dataFlag=BooleanArray(SIZE){
it<medIndex
}
private var medValue = 0
fun init(v:Int):Int{
data[index]=v
if (v < medValue&&(dataFlag[index]||index==medIndex)) {
if (dataFlag[index]) {
dataFlag[index] = false
dataFlag[medIndex] = true
}
medValue = v
data.forEachIndexed { i, v ->
if (dataFlag[i].not() && v > medValue) {
medIndex = i
medValue = v
}
}
} else {
if (v > medValue) {
dataFlag[index] = true
medValue = v
medIndex = index
data.forEachIndexed { i, v ->
if (dataFlag[i] && v < medValue) {
medIndex = i
medValue = v
}
}
dataFlag[medIndex] = false
}
}
index++
if(index==SIZE){
index=0
}
return medValue
}
}
internal
class CMidRFilter(private val SIZE:Int=11) {
private var medIndex=5
private var index = 0
private val data=IntArray(SIZE)
private val dataFlag=BooleanArray(SIZE){
it<medIndex
}
private var medValue = 0
fun init(v:Int):Int{
data[index]=v
if (v < medValue&&(dataFlag[index]||index==medIndex)) {
if (dataFlag[index]) {
dataFlag[index] = false
dataFlag[medIndex] = true
}
medValue = v
data.forEachIndexed { i, v ->
if (dataFlag[i].not() && v > medValue) {
medIndex = i
medValue = v
}
}
} else {
if (v > medValue) {
dataFlag[index] = true
medValue = v
medIndex = index
data.forEachIndexed { i, v ->
if (dataFlag[i] && v < medValue) {
medIndex = i
medValue = v
}
}
dataFlag[medIndex] = false
}
}
index++
if(index==SIZE){
index=0
}
return medValue
}
}
internal
class CMidXFilter(private val SIZE:Int=256) {
private var medIndex=10
private var index = 0
private val data=FloatArray(SIZE)
private val dataFlag=BooleanArray(SIZE){
it<medIndex
}
private var medValue = 0f
fun init(v:Float):Float{
data[index]=v
if (v < medValue&&(dataFlag[index]||index==medIndex)) {
if (dataFlag[index]) {
dataFlag[index] = false
dataFlag[medIndex] = true
}
medValue = v
data.forEachIndexed { i, v ->
if (dataFlag[i].not() && v > medValue) {
medIndex = i
medValue = v
}
}
} else {
if (v > medValue) {
dataFlag[index] = true
medValue = v
medIndex = index
data.forEachIndexed { i, v ->
if (dataFlag[i] && v < medValue) {
medIndex = i
medValue = v
}
}
dataFlag[medIndex] = false
}
}
index++
if(index==SIZE){
index=0
}
return medValue
}
}
}