Electronic – Digital control of electromechanical gauges

analoglow passmosfetoperational-amplifierpwm

I have the exact same scenario as a previous question Digital Control of Analog Gauge but am still having trouble solving.

I have two (fuel and temp) old (circa 1973) electromechanical analog gauges made by VDO that I'd like to control digitally. They are 3 wire (12v, ground, and signal) gauges where the signal was originally connected to a sending unit (fuel float or temperature sender).

I've created a number of circuits and have had some success with the one shown below (using a low pass filter, operational amplifier, and MOSFET) but I haven't got it working well yet.

Digital to Analog Gauge circuit
enter image description here

Because the original gauges use a logarithmic scale of some sort, I've measured and created a map in code that varies the PWM output based on the percentage of full (or hot) that I desire. The range of the pwm used is narrow but it works ok with just one gauge and a consistent voltage from the 12v power supply. However, any slight changes in voltage or resistance in the system, such as varying the input voltage from the 12v power supply, putting power to the instrument lights, or adding the second gauge, changes the calibration and makes the needle move more or less than previously. I am using a single 12v power supply for testing. I have a 12v to micro USB buck converter connected to power the Arduino. I share the ground from the power supply to the ground pin of the Arduino. I use the same 12v and ground from the P/S for power/gnd to the op amp.

Example videos moving through 5 or 6 distinct (cold, normal, half, 3/4, hot or empty, reserve 1/4, half, 3/4, full) steps: https://youtu.be/VGjDCAPXvEQ https://youtu.be/2KRYqxt8-eU

Any suggestions for how to make this reliable?

Components used: Arduino MKR Zero with 12-bit DAC, LM358 Op amp, 2N7000 MOSFET

I don't think the Arduino code is particularly relevant but I'll include it here for completeness. Obviously, this will eventually use fuel and temp info from my CANbus to write the appropriate PWM output but for now I'm just trying to calibrate the output with fixed steps.

int tempStep = 0;
int fuelStep = 0;
int tempIncrement = 1;
int fuelIncrement = 1;

int tempGaugeMap[] = {
  2500, // bottom of cold
  2560, // top of cold
  2600, // quarter
  2635, // half
  2655, // three quarters
  2680, // bottom of hot
  2695 // top of hot
};
unsigned int tempSteps = 6;

int fuelGaugeMap[] = {
  2710, // reserve
  2730, // empty
  2760, // 1/4
  2820, // half
  2900, // 3/4
  3500, //full
};
unsigned int fuelSteps = 5;

void setup() {
  // open a serial connection
  Serial.begin(9600);
  // make our DAC pin an output
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  // 12-bit DAC resolution
  analogWriteResolution(12);
}

void loop() {
  int tempVal = tempGaugeMap[tempStep];
  int fuelVal = fuelGaugeMap[fuelStep];
  
  analogWrite(0, tempVal);
  analogWrite(1, fuelVal);
  
  if(tempStep >= tempSteps) { tempIncrement = -1; }
  if(tempStep == 0) { tempIncrement = 1; }
  tempStep = tempStep + tempIncrement;
 
  if(fuelStep >= fuelSteps) { fuelIncrement = -1; }
  if(fuelStep == 0) { fuelIncrement = 1; }
  fuelStep = fuelStep + fuelIncrement;
 
  delay(1000);
}

I've made some measurements of the gauges themselves as follows:

Temp Gauge Measurements

Fuel Gauge Measurements

Best Answer

Your approach is ultra sensitive because you are driving the gauge open-loop. The opamp circuit has a fixed gain, but it is driving a FET running wide open. Its transconductance changes with temperature, the voltage from drain to source, the phase of the moon, etc, all adding up to no real stability.

There are several ways to improve things. One is to bring the FET inside the opamp control loop. You can do this by disconnecting the right side of R2 from the U1 output, and connecting it to the Q1 drain. <> Q1 is an inverter, so you have to swap the two opamp inputs to compensate for the extra signal inversiion. Also, we need to know the part number of the opamp because not all devices have the output voltage range to do what you want.

Separate from that, the values of R2 and R3 can be increased 10x or even 100x to lower the output stage current.

Another approach is driving the gauge with a current source rather than a voltage source. With the 12 V source and a resistor, determine the current through the gauge at the minimum and maximum indications. These can be used to reconfigure U1 as a voltage controlled current source (actually, current sink).

Update 1:

Another approach is to leave the opamp inputs alone, change Q1 to a bipolar transistor as an emitter follower, connect the collector to +12, connect R2 to the emitter, and move the gauge to between the emitter and GND. The voltage across the gauge will be the voltage at C1 times the opamp circuit gain. The transistor is just a current booster, and adds no voltage gain to the loop. If you know the min and max resistance values of the sender, the opamp gain should be easy to calculate. Note - you might have to add a DC offset, depending on the gauge.

Update 2:

The more I think about this, the more I prefer the Update 1 idea. It removes any sensitivity to the absolute value of the 12 V source. Both the filtered PWM signal and the signal to the gauge are referenced to GND only. My guess is that both the opamp circuit gain and the look-up tables will have to be adjusted, but this probably is the second-best way to go. First-best would be the same circuit modified to be a current source, but you might not need that level of complexity.