ADC calculations - Page 1
Forum section: electronics / projects

author: gnif
author_rank: Unknown
timestamp: May 30, 2020, 05:35:24 am
content: Unfortunately, I never did well in math at school and as such, this is a field I struggle with so please bear with me as I know what I am asking is likely very simple math to work out.I am building a device that uses a current transducer to meter power generated by my solar system, and how much has been stored, etc. I am using a STM32F103C8T which contains a 12-bit ADC and will sample up to 16 channels (iirc). One of the features of this device is that it will let you sample the internal vref so that you can use it to correct for sampling errors due to drift, etc.As I am looking for good accuracy I have used MAX6350 (I had a few floating around) as a precision 5V reference and using two 1K resistors divided it down to 2.5V for the current transducer's vref. This improved the output of the transducer considerably even though I am doing a less than perfect divide by 2 (yes, I should get a MAX6325). To be able to adjust for error I have also fed this 2.5V reference into the ADC.The current transducer is aLSTR 15-NPconfigured for two loops at a nominal 7.5A.So, I have three analog inputs to the mcu:1) Current Transducer Output (CH_CUR)2) Current Transducer VREF (CH_CREF)3) Battery voltage which I am dropping 48V via two zeners and then using another divider network to scale the remainder to the 3.3V ADC input. (CH_VOL)So in software, I have four samples per sampling, the fourth being the STM32's ADC reference (CH_VREF). At the moment what I have done is the following although I question its correctness.Code:const float vref = (4095.0f * 1200.0f) / samples;const float cref = samples * (vref / 2047.5f);const float c = (samples * (cref / 4095.0f) - (cref / 2.0f)) * (7500.0f / (3125.0f - 2500.0f));const float v = samples * (10725.0f / 4095.0f) + 47757.0f;Does this look correct, or am I missing something here? While the results are close to my DC clamp meter, it's still about 500mA off on average.Edit: Forgot to add, here is a sample of the raw samples when there is zero current flow.Code:VREFCREFCURVOL151531412024137615153141202214021513314220211439151431432023136015143141202313661514314220211450151431412021137215143142202413741514314220221347151531402023141415153141202214411515314120231351

author: Kleinstein
author_rank: Super Contributor
timestamp: May 30, 2020, 07:44:29 am
content: The formulas are at least very confusing and overly complicated to the point I can't really understand them. With so many constants inside chances are high there is a mistake included.The current transducer ouputs the result relative the the V_ref signal. So there is no need for a very accurate V_ref for the transducer. This is more like a virtual ground. An accurate V_ref may be needed with for the ADC.Ideally one would use ADC in the µC in a differential mode: one side the the transducer V_ref and the other side to the output.When using the ADC signals as described one would get the current as:I = ADCref/ G /4095 * (CH_Cur - CH_Ref)Here ADref is the ref voltage to the ADC (e.g. 3.3 V) and G = 41.6 mV/A from the transducer data sheet.Using only negative currents one could set the ADC ref. to some 2.5 V from an external ref. Chip. and the Ref_input for the transducer to a slightly smaller fraction (like 98%) so that at zero the ADC would read near maximum and lower when the current goes down.

author: Vovk_Z
author_rank: Super Contributor
timestamp: May 30, 2020, 07:58:33 am
content: Have you checked all Ref voltages?

author: gnif
author_rank: Unknown
timestamp: May 30, 2020, 07:22:24 pm
content: Thanks guys, yes I have checked the ref voltages and@Kleinsteinhas steered me in the correct direction. Here is what I have come up with nowExpected current out = 2.5v as there is zero flowOptimal VREF = 4095*1200/3300 = 1489.1Actual VREF Sample = 1515Error = 1515-1489.1 = -25.9Current Ref Sample = 3141Current Out Sample = 2024Adjusted Ref Sample = 3141 + -25.9 = 3115.10Adjusted Out Sample = 2024 + -25.9 = 1998.10So remembering that `current out` is scaled through a resistor divider network (1.8k / 3.8k), cref is also scaled (1k / 1k), and the current transducer sensitivity is 41.6mV/A but is running with two transformer loops.vref = 1200*4095*1515 = 3.243vcurrent ref = 3300/4095*3115.10*2 = 5.020vcurrent out = (vref/cref)*(3300/4095*cur)current out = (3.243/5.020)*(3300/4095*2024) = 2.492vcurrent out err = 2.5 - 2.492 = 7.61mvacross a bunch of samples the error average is 9.81mVadjusted current out = 2.492v + 9.81mV = 2.502VI = (2.502V - 2.5V) / (0.0416*2) = 0.05AAcross a bunch of samples here is the resulting spread:Code:Raw SamplesAdjusted SamplesConverted to VoltagesOutputVREFERRCREFCURCREFCURVREFCREFCURERRCURA1515-25.90314120243115.101998.103243.565020.672492.397.612502.210.051515-25.90314120223115.101996.103243.565020.672489.9010.102499.71-0.011513-23.90314220213118.101995.103247.855025.512487.7612.242497.57-0.061514-24.90314320233118.101997.103245.715025.512491.908.102501.710.041514-24.90314120233116.101997.103245.715022.292490.309.702500.110.001514-24.90314220213117.101995.103245.715023.902488.6111.392498.42-0.041514-24.90314120213116.101995.103245.715022.292487.8112.192497.62-0.061514-24.90314220243117.101998.103245.715023.902492.357.652502.160.051514-24.90314220223117.101996.103245.715023.902489.8510.152499.66-0.011515-25.90314020233114.101997.103243.565019.062490.359.652500.160.001515-25.90314120223115.101996.103243.565020.672489.9010.102499.71-0.011515-25.90314120233115.101997.103243.565020.672491.158.852500.960.02

author: Vovk_Z
author_rank: Super Contributor
timestamp: May 30, 2020, 09:24:41 pm
content: It has to have a calibration procedure I think.

author: gnif
author_rank: Unknown
timestamp: May 30, 2020, 10:25:16 pm
content: Quote from: Vovk_Z on May 30, 2020, 09:24:41 pmIt's not calibration related, the STM32's ADC has a calibration that is done prior, and the 5V reference is providing 5.0001v with 1ppm/°C accuracy. This question is how to correctly calculate the current flow based on all known factors.The only part of the design that is calibration related is the resistor divider networks used to scale the voltages, and has been accounted for.

author: gnif
author_rank: Unknown
timestamp: June 04, 2020, 11:00:17 pm
content: Just a follow up on this, I was still going about things completely wrong, the VREFINT voltage is to be used in a different manner entirely.Code:volts = sample * 1200 / vrefint

author: Nominal Animal
author_rank: Super Contributor
timestamp: June 05, 2020, 10:19:38 am
content: When working this stuff out, I like to model the measurements first, with error sources. In your case, if you let the ADC do its internal calibration every now and then, the datasheet claims your total error is at most two units in least significant position, i.e. ±2/4096 ≃ ±0.04884%, so it is pretty safe to assume the ADC itself is linear without offset. Also, the ST datasheet says that the ADC unit is VREF/4096 (page 77, ideal sample size).So, the ADC reading isADC = 4096 × V / VREFwhere V is the voltage being measured. The internal voltage reference can have 3% error. (Nominal 1.20 V, but can vary between 1.16 V and 1.24 V; 0.04 V / 1.20 V ≃ 3.33%). So, I wouldn't use the internal reference for anything if I can avoid it. But, if you use the external 2.5V reference, you can only measure 0 - 2.5V. (VFQFPN and LQFP packages don't even have an external VREF pin, it is internally connected to VDDA.)The transducer output according to its datasheet isVOUT= VREF± 0.625× I / IREFwhere I is the current being measured. The 0.625means 0.625 volts, and is characteristic for the transducer, and does not depend on the reference voltage.Which samples use which reference voltage?Personally, I would have used two voltage dividers from the 5V precision source: one at 3.2V or so (assuming your power supply is greater than that), and one at 2.0V or so (since this transducer doesn't like smaller reference voltages). The 3.2V would be wired directly to the VREF+ pin (so VREF), and you'd measure the actual voltage using a good voltmeter for calibration purposes. The 2.0V would go to the transducer (so VIREF), and optionally to a free analog pin so you can measure it at run time; any variation (outside ±2, per datasheet) in it indicates something is seriously wrong.Then, if the sign of the current I indicates the direction of the current flow, the ADC reading would then beADCI= 4096 × VOUT/ VREF= 4096 × VIREF/ VREF+ 2560× I / (IREF× VREF)and the estimate for the current (from solving the above for I) would beI = (ADCIVREF- 4096 × VIREF) × IREF/ 2560The resolution would be around 10 mA, but accuracy would depend on how precisely you know or measure the voltage references. I'd probably use integer arithmetic for this, with currents in milliamps and voltages in millivolts.