wideband/firmware/sampling.cpp

107 lines
3.0 KiB
C++
Raw Normal View History

2020-10-29 02:55:55 -07:00
#include "sampling.h"
#include "ch.h"
#include "hal.h"
2020-10-30 02:03:12 -07:00
#include "wideband_config.h"
2021-02-25 22:39:51 -08:00
#include "port.h"
#include "io_pins.h"
2020-10-29 02:55:55 -07:00
// Stored results
static float nernstAc = 0;
static float nernstDc = 0;
2022-04-06 01:08:40 -07:00
static float pumpCurrentSenseVoltage = 0;
static float internalBatteryVoltage = 0;
2020-10-29 02:55:55 -07:00
constexpr float f_abs(float x)
{
return x > 0 ? x : -x;
}
static THD_WORKING_AREA(waSamplingThread, 256);
static void SamplingThread(void*)
{
float r_2 = 0;
float r_3 = 0;
while(true)
{
auto result = AnalogSample();
2021-01-19 00:24:47 -08:00
// Toggle the pin after sampling so that any switching noise occurs while we're doing our math instead of when sampling
palTogglePad(NERNST_ESR_DRIVER_PORT, NERNST_ESR_DRIVER_PIN);
2021-01-19 00:24:47 -08:00
2020-10-29 02:55:55 -07:00
float r_1 = result.NernstVoltage;
// r2_opposite_phase estimates where the previous sample would be had we not been toggling
// AKA the absolute value of the difference between r2_opposite_phase and r2 is the amplitude
// of the AC component on the nernst voltage. We have to pull this trick so as to use the past 3
// samples to cancel out any slope in the DC (aka actual nernst cell output) from the AC measurement
2020-10-29 17:22:18 -07:00
// See firmware/sampling.png for a drawing of what's going on here
2020-10-29 02:55:55 -07:00
float r2_opposite_phase = (r_1 + r_3) / 2;
2020-10-29 03:11:48 -07:00
// Compute AC (difference) and DC (average) components
2021-06-03 20:50:39 -07:00
float nernstAcLocal = f_abs(r2_opposite_phase - r_2);
2020-10-29 02:55:55 -07:00
nernstDc = (r2_opposite_phase + r_2) / 2;
2021-06-03 20:50:39 -07:00
nernstAc =
(1 - ESR_SENSE_ALPHA) * nernstAc +
ESR_SENSE_ALPHA * nernstAcLocal;
2020-12-15 14:41:09 -08:00
// Exponential moving average (aka first order lpf)
pumpCurrentSenseVoltage =
(1 - PUMP_FILTER_ALPHA) * pumpCurrentSenseVoltage +
PUMP_FILTER_ALPHA * (result.PumpCurrentVoltage - result.VirtualGroundVoltageInt);
2020-10-29 02:55:55 -07:00
2022-04-06 01:08:40 -07:00
#ifdef BATTERY_INPUT_DIVIDER
internalBatteryVoltage = result.BatteryVoltage;
#endif
2020-10-29 02:55:55 -07:00
// Shift history over by one
r_3 = r_2;
r_2 = r_1;
}
}
void StartSampling()
{
adcStart(&ADCD1, nullptr);
chThdCreateStatic(waSamplingThread, sizeof(waSamplingThread), NORMALPRIO + 5, SamplingThread, nullptr);
}
float GetNernstAc()
{
return nernstAc;
}
float GetSensorInternalResistance()
{
// Sensor is the lowside of a divider, top side is 22k, and 3.3v AC pk-pk is injected
2021-01-17 03:31:44 -08:00
float totalEsr = ESR_SUPPLY_R / (VCC_VOLTS / GetNernstAc() - 1);
// There is a resistor between the opamp and Vm sensor pin. Remove the effect of that
// resistor so that the remainder is only the ESR of the sensor itself
return totalEsr - VM_RESISTOR_VALUE;
2020-10-29 02:55:55 -07:00
}
float GetNernstDc()
{
return nernstDc;
}
float GetPumpNominalCurrent()
{
// Gain is 10x, then a 61.9 ohm resistor
// Effective resistance with the gain is 619 ohms
// 1000 is to convert to milliamperes
2020-10-31 14:54:50 -07:00
constexpr float ratio = -1000 / (PUMP_CURRENT_SENSE_GAIN * LSU_SENSE_R);
2020-10-29 02:55:55 -07:00
return pumpCurrentSenseVoltage * ratio;
}
2022-04-06 01:08:40 -07:00
float GetInternalBatteryVoltage()
{
return internalBatteryVoltage;
}