wideband/firmware/sampling.cpp

163 lines
5.3 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"
#include "livedata.h"
2020-10-29 02:55:55 -07:00
#include <rusefi/interpolation.h>
2020-10-29 02:55:55 -07:00
// Stored results
struct measure_results {
float nernstAc;
float nernstDc;
float pumpCurrentSenseVoltage;
float internalBatteryVoltage;
};
static struct measure_results results[AFR_CHANNELS];
2020-10-29 02:55:55 -07:00
// Last point is approximated by the greatest measurable sensor resistance
2023-02-14 13:53:52 -08:00
static const float lsu49TempBins[] = { 80, 100, 150, 200, 250, 300, 350, 400, 450, 550, 650, 800, 1000, 1200, 2500, 4500 };
static const float lsu49TempValues[] = { 1030, 972, 888, 840, 806, 780, 761, 744, 729, 703, 686, 665, 642, 628, 567, 500 };
static const float lsu42TempBins[] = { 35, 40, 50, 60, 70, 80, 90, 100, 120, 150, 200, 250, 300, 400, 450, 500, 600, 700, 800, 900, 1000, 1100 };
static const float lsu42TempValues[] = { 1199, 961, 857, 806, 775, 750, 730, 715, 692, 666, 635, 613, 598, 574, 564, 556, 543, 535, 528, 521, 514, 503 };
static const float lsuAdvTempBins[] = { 53, 96, 130, 162, 184, 206, 239, 278, 300, 330, 390, 462, 573, 730, 950, 1200, 1500, 1900, 2500, 3500, 5000, 6000 };
static const float lsuAdvTempValues[] = { 1198, 982, 914, 875, 855, 838, 816, 794, 785, 771, 751, 732, 711, 691, 671, 653, 635, 614, 588, 562, 537, 528 };
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[AFR_CHANNELS] = {0};
float r_3[AFR_CHANNELS] = {0};
2020-10-29 02:55:55 -07:00
chRegSetThreadName("Sampling");
SetupESRDriver(GetSensorType());
/* GD32: Insert 20us delay after ADC enable */
chThdSleepMilliseconds(1);
2020-10-29 02:55:55 -07:00
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
ToggleESRDriver(GetSensorType());
2021-01-19 00:24:47 -08:00
for (int ch = 0; ch < AFR_CHANNELS; ch++) {
measure_results &res = results[ch];
float r_1 = result.ch[ch].NernstVoltage;
2020-10-29 02:55:55 -07:00
// 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
// See firmware/sampling.png for a drawing of what's going on here
float r2_opposite_phase = (r_1 + r_3[ch]) / 2;
2020-10-29 02:55:55 -07:00
// Compute AC (difference) and DC (average) components
float nernstAcLocal = f_abs(r2_opposite_phase - r_2[ch]);
res.nernstDc = (r2_opposite_phase + r_2[ch]) / 2;
2020-10-29 02:55:55 -07:00
res.nernstAc =
(1 - ESR_SENSE_ALPHA) * res.nernstAc +
ESR_SENSE_ALPHA * nernstAcLocal;
2021-06-03 20:50:39 -07:00
// Exponential moving average (aka first order lpf)
res.pumpCurrentSenseVoltage =
(1 - PUMP_FILTER_ALPHA) * res.pumpCurrentSenseVoltage +
PUMP_FILTER_ALPHA * (result.ch[ch].PumpCurrentVoltage - result.VirtualGroundVoltageInt);
2020-10-29 02:55:55 -07:00
#ifdef BATTERY_INPUT_DIVIDER
res.internalBatteryVoltage = result.ch[ch].BatteryVoltage;
#endif
2022-04-06 01:08:40 -07:00
// Shift history over by one
r_3[ch] = r_2[ch];
r_2[ch] = r_1;
}
#if defined(TS_ENABLED)
/* tunerstudio */
SamplingUpdateLiveData();
#endif
2020-10-29 02:55:55 -07:00
}
}
void StartSampling()
{
adcStart(&ADCD1, nullptr);
chThdCreateStatic(waSamplingThread, sizeof(waSamplingThread), NORMALPRIO + 5, SamplingThread, nullptr);
}
float GetNernstAc(int ch)
2020-10-29 02:55:55 -07:00
{
return results[ch].nernstAc;
2020-10-29 02:55:55 -07:00
}
float GetSensorInternalResistance(int ch)
2020-10-29 02:55:55 -07:00
{
// Sensor is the lowside of a divider, top side is GetESRSupplyR(), and 3.3v AC pk-pk is injected
float totalEsr = GetESRSupplyR() / (VCC_VOLTS / GetNernstAc(ch) - 1);
2021-01-17 03:31:44 -08:00
// 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 GetSensorTemperature(int ch)
{
float esr = GetSensorInternalResistance(ch);
2022-05-18 23:45:42 -07:00
if (esr > 5000)
{
return 0;
}
switch (GetSensorType()) {
case SensorType::LSU49:
return interpolate2d(esr, lsu49TempBins, lsu49TempValues);
case SensorType::LSU42:
return interpolate2d(esr, lsu42TempBins, lsu42TempValues);
case SensorType::LSUADV:
return interpolate2d(esr, lsuAdvTempBins, lsuAdvTempValues);
}
return 0;
}
float GetNernstDc(int ch)
2020-10-29 02:55:55 -07:00
{
return results[ch].nernstDc;
2020-10-29 02:55:55 -07:00
}
float GetPumpNominalCurrent(int ch)
2020-10-29 02:55:55 -07:00
{
// 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);
return results[ch].pumpCurrentSenseVoltage * ratio;
2020-10-29 02:55:55 -07:00
}
2022-04-06 01:08:40 -07:00
float GetInternalBatteryVoltage(int ch)
2022-04-06 01:08:40 -07:00
{
// Dual HW can measure heater voltage for each channel
// by measuring voltage on Heater- while FET is off
// TODO: rename function?
return results[ch].internalBatteryVoltage;
2022-04-06 01:08:40 -07:00
}