Most thermocouples are heavily low pass filtered, as generally they are not a fast response. A 1 sec RC filter is common, using 1M and a 1uF good quality ( not ceramic, electrolytic or tantalum) polyester or polycarbonate film capacitor between the amplifier and the ADC input. Most of the spikes are noise coupled into the thermocouple leads.
//call this function very regularly
//uses signed integers because of intermediate negative values in calculation
signed int read_analogue_iir(unsigned char ad_channel) {
//result = oldresult + (( newresult - oldresult) / hardness )
//where hardness is the settling time
//info here: http://electronics.stackexchange.com/questions/30370/fast-and-memory-efficient-moving-average-calculation
#define IIR_HARDNESS 64 //bigger numbers increase smoothing. Use power of 2 numbers.
static signed int prev_val; //for illustration only, use array with 'ad_channel' as index, otherwise you'll need a variable for each channel.
signed int temp;
temp = (signed int)(sample_adc(ad_channel)); // calls function to get ADC sample from 'ad_channel'.
prev_val = prev_val + ( (temp - prev_val) / IIR_HARDNESS ); //everything MUST be signed, NOT unsigned.
return prev_val;
}
int operator()(int sample) {
int result = a0*sample + a1*x1 + a2*x2 - a3*y1 - a4*y2;
x2 = x1;
x1 = sample;
y2 = y1;
y1 = result;
return result;
}
That code makes a lot of sense, ensuring small changes between readings and preserving memory space for averaging. However i must admit the biquadratic filters are still a litt confusing to me, i never managed to get my head around understanding the frequency domain. The thing i am not sure about is what a hefty capacitor would be in this situation? I have modified my schematic to include the new filtering and i think it will certainly improve my results. I also ensured that i have a bypass capacitor right next to the supply & reference of my ADC so as to remove some of the noise from there.
@andy - that biquad filter looks good, never made a digital implementation but have used their analogue counterparts a few times in audio applications. Looks like you need a micro with an FPU to use it, assuming those coefficients are doubles and not ints.
result = (a0*sample + a1*x1 + a2*x2 - a3*y1 - a4*y2)/scale;
I am working on something very similar that I am going to write up very soon.
The biquad seems to work pretty well with fixed point at run time. At "compile" time, you'll need floating point to calculate the coefficients. I'm using 32-bit values in B16 to represent the filter state. That just multiplies the fractional coefficients you'd normally use by 2^15. Each term of the polynomial has the same scaling applied, so at run time it can be evaluated in B16 with the result converted back to "normal" with a single division:Code: [Select]result = (a0*sample + a1*x1 + a2*x2 - a3*y1 - a4*y2)/scale;
My sample values are only 12-bits, so I think it's reasonably safe from overflow. If it did overflow (depending on coefficients), I'd look at re-ordering the polynomial terms to squeeze out a little more before messing with precision.
I'm not sure if this the proper way to do it as I don't do electronics and I'm crap at math but it does work for me!
That LT app note looks very useful, it's worth thinking about cold junction compensation if you need absolute accuracy - that's what the LTC1025 is doing in the diagram on page 2.
I've has some bad experience with LTC1025 - the readings were smooth at low temperatures, but started behaving wildly at higer temps. And it was only noisy while connected to a thermocouple in kiln, I couldn't simulate this with external voltage. But when I removed cold junction compensation of LTC1025 - the noise just went away. I'm attaching two plots to ilustrate that.
You need to put the feedback cap in parallel with the feedback resistor - so R6 goes between the op-amp output and the inverting input and C7 goes in parallel with R6. You'll also need another cap across R8, the same value as the cap across R6.
'Hefty' means about 100nF - that's a good starting point. Use polyester film or polypropylene. You might need 47nF or 220nF, or something like that. (Normally capacitors around op-amp feedback loops are in the order 10pF or so, so 100nF is pretty 'hefty' by those standards).
If you find the op-amp oscillates with the feedback caps (it shouldn't do, but might) then put a 47R series resistor right at the op-amp's output.
That LT app note looks very useful, it's worth thinking about cold junction compensation if you need absolute accuracy - that's what the LTC1025 is doing in the diagram on page 2.
You should be ok with this belt and braces approach - the op-amp feedback caps help prevent the op-amp amplifying noise and RFI from the thermocouple, the RC filter attenuates noise even more to help prevent aliasing at the ADC, and the IIR filter gets rid of acquisition noise. You can even tweak the gain of the diff-amp to give you more output voltage so you use more of the ADC's range, as long as the maximum temperature you expect results in a voltage slightly less than the ADC reference voltage. This improves signal-to-noise ratio as well as measurement resolution and helps even more. That's the belt-and-braces-with-cable-tie-and-gaffer-tape approach.#
Cool, I'd be interested to read that!
I took the easy option with the ad595 as it has 10mV per 1'c and cold point compensation; I used a Haven Thermo-Calibrator to simulate temperatures.
When I first used the Thermo-Cal it actually messed up my readings but I wasn't sure why; So I hooked it up to my el-cheapo old scope and found some spikes on the line, I tried averaging but If I fell on any spikes it just messed it up. So I opted to take multiple samples and discard any values that weren't within the set tolerance.
The upper channel in the pic shows the spikes; the lower channel shows little blips, the blips are my uC sampling periods output on channel 2 via a gpio pin; So only when the blips miss any spikes the value is returned. I'm not sure if this the proper way to do it as I don't do electronics and I'm crap at math but it does work for me!