mirror of
https://github.com/mck1117/wideband.git
synced 2026-09-30 09:57:06 -04:00
Multichannel (#134)
* Multichannel AFR * heater: fixes for multi channel mode * f1_dual: fix configuration names * pump_dac: fixes for multi-channel mode * pwm: fixes for multichannel mode * pump_control: reference instead of pointer * sampling: reference instead of pointer * heater_control: reference instead of pointer * sampling: comment about heater/battery voltage * f0_module: fixes for multi-channel update * f1_rev2: fix for multichannel AFR * hello rev 3 Co-authored-by: rusefillc <sdfsdfqsf2334234234>
This commit is contained in:
@@ -12,10 +12,14 @@
|
||||
#include <rusefi/interpolation.h>
|
||||
|
||||
// Stored results
|
||||
static float nernstAc = 0;
|
||||
static float nernstDc = 0;
|
||||
static float pumpCurrentSenseVoltage = 0;
|
||||
static float internalBatteryVoltage = 0;
|
||||
struct measure_results {
|
||||
float nernstAc;
|
||||
float nernstDc;
|
||||
float pumpCurrentSenseVoltage;
|
||||
float internalBatteryVoltage;
|
||||
};
|
||||
|
||||
static struct measure_results results[AFR_CHANNELS];
|
||||
|
||||
// Last point is approximated by the greatest measurable sensor resistance
|
||||
static const float lsu49TempBins[] = { 80, 150, 200, 250, 300, 350, 400, 450, 550, 650, 800, 1000, 1200, 2500, 5000 };
|
||||
@@ -30,51 +34,51 @@ static THD_WORKING_AREA(waSamplingThread, 256);
|
||||
|
||||
static void SamplingThread(void*)
|
||||
{
|
||||
float r_2 = 0;
|
||||
float r_3 = 0;
|
||||
float r_2[AFR_CHANNELS] = {0};
|
||||
float r_3[AFR_CHANNELS] = {0};
|
||||
|
||||
/* GD32: Insert 20us delay after ADC enable */
|
||||
chThdSleepMilliseconds(1);
|
||||
|
||||
while(true)
|
||||
{
|
||||
/* TODO: run for all channels */
|
||||
int ch = 0;
|
||||
|
||||
auto result = AnalogSample();
|
||||
|
||||
// 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);
|
||||
|
||||
float r_1 = result.ch[ch].NernstVoltage;
|
||||
for (int ch = 0; ch < AFR_CHANNELS; ch++) {
|
||||
measure_results &res = results[ch];
|
||||
float r_1 = result.ch[ch].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
|
||||
// See firmware/sampling.png for a drawing of what's going on here
|
||||
float r2_opposite_phase = (r_1 + r_3) / 2;
|
||||
// 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;
|
||||
|
||||
// Compute AC (difference) and DC (average) components
|
||||
float nernstAcLocal = f_abs(r2_opposite_phase - r_2);
|
||||
nernstDc = (r2_opposite_phase + r_2) / 2;
|
||||
// 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;
|
||||
|
||||
nernstAc =
|
||||
(1 - ESR_SENSE_ALPHA) * nernstAc +
|
||||
ESR_SENSE_ALPHA * nernstAcLocal;
|
||||
res.nernstAc =
|
||||
(1 - ESR_SENSE_ALPHA) * res.nernstAc +
|
||||
ESR_SENSE_ALPHA * nernstAcLocal;
|
||||
|
||||
// Exponential moving average (aka first order lpf)
|
||||
pumpCurrentSenseVoltage =
|
||||
(1 - PUMP_FILTER_ALPHA) * pumpCurrentSenseVoltage +
|
||||
PUMP_FILTER_ALPHA * (result.ch[ch].PumpCurrentVoltage - result.VirtualGroundVoltageInt);
|
||||
// Exponential moving average (aka first order lpf)
|
||||
res.pumpCurrentSenseVoltage =
|
||||
(1 - PUMP_FILTER_ALPHA) * res.pumpCurrentSenseVoltage +
|
||||
PUMP_FILTER_ALPHA * (result.ch[ch].PumpCurrentVoltage - result.VirtualGroundVoltageInt);
|
||||
|
||||
#ifdef BATTERY_INPUT_DIVIDER
|
||||
internalBatteryVoltage = result.ch[ch].BatteryVoltage;
|
||||
#endif
|
||||
#ifdef BATTERY_INPUT_DIVIDER
|
||||
res.internalBatteryVoltage = result.ch[ch].BatteryVoltage;
|
||||
#endif
|
||||
|
||||
// Shift history over by one
|
||||
r_3 = r_2;
|
||||
r_2 = r_1;
|
||||
// Shift history over by one
|
||||
r_3[ch] = r_2[ch];
|
||||
r_2[ch] = r_1;
|
||||
}
|
||||
|
||||
#if defined(TS_ENABLED)
|
||||
/* tunerstudio */
|
||||
@@ -89,24 +93,24 @@ void StartSampling()
|
||||
chThdCreateStatic(waSamplingThread, sizeof(waSamplingThread), NORMALPRIO + 5, SamplingThread, nullptr);
|
||||
}
|
||||
|
||||
float GetNernstAc()
|
||||
float GetNernstAc(int ch)
|
||||
{
|
||||
return nernstAc;
|
||||
return results[ch].nernstAc;
|
||||
}
|
||||
|
||||
float GetSensorInternalResistance()
|
||||
float GetSensorInternalResistance(int ch)
|
||||
{
|
||||
// Sensor is the lowside of a divider, top side is 22k, and 3.3v AC pk-pk is injected
|
||||
float totalEsr = ESR_SUPPLY_R / (VCC_VOLTS / GetNernstAc() - 1);
|
||||
float totalEsr = ESR_SUPPLY_R / (VCC_VOLTS / GetNernstAc(ch) - 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;
|
||||
}
|
||||
|
||||
float GetSensorTemperature()
|
||||
float GetSensorTemperature(int ch)
|
||||
{
|
||||
float esr = GetSensorInternalResistance();
|
||||
float esr = GetSensorInternalResistance(ch);
|
||||
|
||||
if (esr > 5000)
|
||||
{
|
||||
@@ -116,21 +120,24 @@ float GetSensorTemperature()
|
||||
return interpolate2d(esr, lsu49TempBins, lsu49TempValues);
|
||||
}
|
||||
|
||||
float GetNernstDc()
|
||||
float GetNernstDc(int ch)
|
||||
{
|
||||
return nernstDc;
|
||||
return results[ch].nernstDc;
|
||||
}
|
||||
|
||||
float GetPumpNominalCurrent()
|
||||
float GetPumpNominalCurrent(int ch)
|
||||
{
|
||||
// Gain is 10x, then a 61.9 ohm resistor
|
||||
// Effective resistance with the gain is 619 ohms
|
||||
// 1000 is to convert to milliamperes
|
||||
constexpr float ratio = -1000 / (PUMP_CURRENT_SENSE_GAIN * LSU_SENSE_R);
|
||||
return pumpCurrentSenseVoltage * ratio;
|
||||
return results[ch].pumpCurrentSenseVoltage * ratio;
|
||||
}
|
||||
|
||||
float GetInternalBatteryVoltage()
|
||||
float GetInternalBatteryVoltage(int ch)
|
||||
{
|
||||
return internalBatteryVoltage;
|
||||
// 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user