-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathTbsShieldRpm.cpp
144 lines (124 loc) · 3.91 KB
/
TbsShieldRpm.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <Arduino.h>
#include "TbsShieldRpm.h"
const uint8_t ips1Pin = A0;
const uint8_t ips2Pin = A1;
const uint8_t ips3Pin = A2;
const uint8_t ips4Pin = A3;
/// <summary>
/// This is the smoothing factor used for the 1st order discrete Low-Pass filter
/// The cut-off frequency fc = fs * K/(2*PI*(1-K))
/// </summary>
const int16_t LowPassFilterCoefDiv = 10; // was 10n// 0.1; original was *, due to int now /
TbsShieldRpm::TbsShieldRpm(uint8_t channelCount) :
m_isFilteringInitialized(false),
m_noiseMaxAmplitude(0),
m_channelCount(channelCount),
m_prevOptimal(channelCount),
m_sampleCalibrate(channelCount)
{
m_sampleCycle = new SampleCycle[channelCount];
}
void TbsShieldRpm::Setup()
{
// sensor setup
analogRead(ips1Pin);
analogRead(ips2Pin);
analogRead(ips3Pin);
analogRead(ips4Pin);
ClearSamples();
}
uint8_t TbsShieldRpm::ReadAllSamples(bool isIgnoringCycles)
{
uint8_t channelsReady = 0;
Sample sample(m_channelCount);
Sample optimalFiltered(m_channelCount);
// read values, back to back for close spatial time
//
sample.ips[0] = analogRead(ips1Pin);
sample.ips[1] = analogRead(ips2Pin);
sample.ips[2] = analogRead(ips3Pin);
sample.ips[3] = analogRead(ips4Pin);
// filtering
//
if (!m_isFilteringInitialized)
{
InitFilteringOnFirstSample(sample);
}
// calc optimal filtered
for (uint8_t channelIndex = 0; channelIndex < m_channelCount; ++channelIndex)
{
int16_t value = FastLowAmplitudeNoiseFilter(sample.ips[channelIndex], m_prevOptimal.ips[channelIndex]);
optimalFiltered.ips[channelIndex] = value;
if (isIgnoringCycles)
{
// just track min and max
m_sampleCycle[channelIndex].Include( value );
}
else
{
if (m_sampleCycle[channelIndex].Track( m_prevOptimal.ips[channelIndex], value ))
{
channelsReady++;
}
}
}
m_prevOptimal = optimalFiltered;
return channelsReady;
}
void TbsShieldRpm::ClearSamples()
{
m_isFilteringInitialized = false;
for (uint8_t channelIndex = 0; channelIndex < m_channelCount; ++channelIndex)
{
m_sampleCycle[channelIndex].Clear();
m_sampleCycle[channelIndex].SetTriggers(m_maxCycle, m_centerCycle, m_minCycle);
}
}
void TbsShieldRpm::InitFilteringOnFirstSample(const Sample& sample)
{
m_prevOptimal = sample;
m_isFilteringInitialized = true;
}
void TbsShieldRpm::CalibrateAtZeroWithSamples()
{
int16_t noiseRange = 0;
for (uint8_t channelIndex = 0; channelIndex < m_channelCount; ++channelIndex)
{
m_sampleCalibrate.ips[channelIndex] = SampleAverage(channelIndex);
noiseRange = max( noiseRange, SampleMax(channelIndex) - SampleMin(channelIndex) );
}
m_noiseMaxAmplitude = noiseRange / 2;
}
void TbsShieldRpm::CalibrateCyclesWithSamples()
{
int32_t sum = 0;
m_maxCycle = 32767; // looking for the lowest of the max
m_minCycle = -32768; // looking for the highest of the min
for (uint8_t channelIndex = 0; channelIndex < m_channelCount; ++channelIndex)
{
sum += SampleAverage(channelIndex);
m_maxCycle = min( m_maxCycle, SampleMax(channelIndex));
m_minCycle = max( m_minCycle, SampleMin(channelIndex));
}
m_centerCycle = sum / m_channelCount;
}
/// <summary>
/// discrete low-magnitude fast low-pass filter used to remove noise from raw accelerometer while allowing fast trending on high amplitude changes
/// </summary>
/// <param name="newInputValue">New input value (latest sample)</param>
/// <param name="priorOutputValue">The previous (n-1) output value (filtered, one sampling period ago)</param>
/// <returns>The new output value</returns>
int16_t TbsShieldRpm::FastLowAmplitudeNoiseFilter(int16_t newInputValue, int16_t priorOutputValue) const
{
int16_t newOutputValue = newInputValue;
int16_t diff = newInputValue - priorOutputValue;
if (abs(diff) < m_noiseMaxAmplitude)
{
// Simple low-pass filter
newOutputValue = priorOutputValue + diff / LowPassFilterCoefDiv;
}
return newOutputValue;
}