| Electronics > Projects, Designs, and Technical Stuff |
| 3rd order Sallen Key Unity Gain LPF - stability question |
| << < (6/6) |
| JDW:
--- Quote from: Someone on April 26, 2020, 06:40:28 am --- --- Quote from: JDW on April 26, 2020, 03:03:03 am ---despite the fact it's not possible to simulate the Microchip Op-Amp in LTSpice. --- End quote --- The MCP601 can be simulated in LTspice, but that requires a person with the motivation to do your work for you. --- End quote --- I must assume you mean: "build a custom model of the Microchip MP601 Op-Amp IC from scratch in LTspice." I will take that under consideration. But as to your "...do your work for you" jab against me, such overlooks the fact that whenever anyone posts on an online forum, other people often chime it in to help, which at least partially amounts to "doing work for the original poster." I would like to repeat my humble thanks to Jay_Diddy_B. Some seem to contend that you offered me too much assistance, but I am sincerely grateful, Jay, not only in that your simulations can help put my feeble brain on the right track, but the fact that this being an open and public forum can no doubt help others as well in the future. Thank you, Jay! --- Quote from: Siwastaja on April 26, 2020, 09:51:11 am ---Note the extra RC filter referred to by nctnico is required due to special input characteristics of SAR ADCs. If you don't like the idea, you can think about it being a part of the ADC, not part of your filter. Though, this extra RC filter can participate in your filter response, as well. See ADC datasheets and appnotes for more information. Typically, R is small like 10-50 ohms, and C is small as well, some hundreds of pF. Often, with the suggested values (by the ADC manufacturer), the corner frequency of the RC is far above of the required Nyquist frequency, so it does not work for anti-aliasing. It's to filter large current spikes only. --- End quote --- I certainly appreciate your very kindly having shared that insight on the RC filter! At the same time though, I would like to humbly ask you one question. Isn't that overthinking the current design? As I mentioned in my opening post, I am not doing precision A-to-D scanning of complex waveforms. All my circuit is doing is just looking for 2 voltage levels with a rather wide tolerance: Vol- pressed: 2.32v (ADC scanning tolerance to confirm a Vol- press: 1.6V~2.6V) Vol+ pressed: 1.44v (ADC scanning tolerance to confirm a Vol+ press: 0.7V~1.6V) (Voltages being scanned for from a car's steering wheel Audio keypad.) I would now like to mention one more thing. I was presented with an existing product on the market that does something similar, using a single ADC pin of an PIC12F1571 connected only to a single 22k-ohm 5% resistor to the outside world (i.e., connected straight to the car's output from the steering wheel Audio keypad). The PIC datasheet makes it abundantly clear that the source impedance should NOT be higher than 10k-ohm, and yet we have this product which has a 22k-ohm resistor, which adds to the resistances on the car side, which can be a maximum of 3k-ohm! And yet, I was told this product has been on the market for 3 years and has very few customer returns or complaints, which implies it does the voltage scanning just fine. But rather than just blindly copy what this other company did by putting ONLY a 22k-ohm resistor on my ADC input, which goes against what the PIC datasheet says (in my case, I am using a PIC16F1503), I am adding an op-amp LPF to ensure the source impedance seen by the ADC pin is very low, and my circuit also protects the PIC better than a mere resistor in the even of an incoming voltage spike, which could be 60V or even higher (albeit for a short duration). (My clamping diode D1 shown in my schematic in my opening post in large part deals with those incoming surges.) ADC resolution on the PIC12F1571 and on the PIC16F1503 is 10-bits. And so, my existing LPF design is, at least in my opinion, adequately attenuating external noise (from the car side). The only thing my current design does not have is the RC filter you spoke of, which apparently "attenuates the kick from switched capacitors in the ADC's input" as per this article: https://www.analog.com/en/analog-dialogue/articles/front-end-amp-and-rc-filter-design.html As that article also states, the addition of an RC filter on the OUTPUT of an op-amp affects Settling Time. But in the case of my design, I have calculated the acquisition time to be about just under 5usec and in my Assembly code controlling the PIC16F1503, I have added a 20usec. delay to give adequate safety margin for my ADC input captures. I also have added a 50msec. delay between captures. In other words, I only sample the steering wheel keypad as fast as once every 50ms, with each capture duration being timed at no less than 20us. In my breadboard testing thus far, I've not had any issues. My thanks to everyone who have very kindly contributed in a positive way to this thread. I sincerely appreciated the hand-holding. It's been a learning experience. |
| Siwastaja:
--- Quote from: JDW on April 27, 2020, 01:09:58 am --- --- Quote from: Siwastaja on April 26, 2020, 09:51:11 am ---Note the extra RC filter referred to by nctnico is required due to special input characteristics of SAR ADCs. If you don't like the idea, you can think about it being a part of the ADC, not part of your filter. Though, this extra RC filter can participate in your filter response, as well. See ADC datasheets and appnotes for more information. Typically, R is small like 10-50 ohms, and C is small as well, some hundreds of pF. Often, with the suggested values (by the ADC manufacturer), the corner frequency of the RC is far above of the required Nyquist frequency, so it does not work for anti-aliasing. It's to filter large current spikes only. --- End quote --- I certainly appreciate your very kindly having shared that insight on the RC filter! At the same time though, I would like to humbly ask you one question. Isn't that overthinking the current design? As I mentioned in my opening post, I am not doing precision A-to-D scanning of complex waveforms. All my circuit is doing is just looking for 2 voltage levels with a rather wide tolerance --- End quote --- For this nearly DC operation, I have hard time understanding why you are specifying a 3rd order lowpass filter at all, I think this is unnecessary complication. Just use a first-order RC filter to begin with, no opamps required. C can be fairly large, like 100nF, R can be large enough (up to 10k?) to protect against excessive current into ADC-integrated clamp diodes, just sample at 20 samples/second or so, and you are done with extremely low complexity and part count. Detect presses by looking if you get the same within-the-range-of-that-button voltage reading for 3-4 consequtive samples. Higher order anti-alias LPFs matter when we require higher frequency AC performance, and low-noise results, and if we have a lot of out-of-band high-frequency noise that would otherwise alias to our band of interest. For your case, none of these seem to be the case. |
| JDW:
Thank you for your suggestion, however I have already covered the use of only a RC filter earlier in this thread. It’s not a simple matter of just using a maximum of a 10K resistor in an RC filter because as I said before the car side keypad has up to 3K of source resistance. So when you factor in tolerances, any RC filter you would choose to design with need to have no more than a 6K resistor. Again, the ADC requirement specifies a “maximum“ of 10 K on source impedance. And as you decrease the resistance in snEC filter you will need to increase the capacitance, and as I said before I preferred to have smaller capacitors along the lines of nanofarads to keep the capacitor discharge time short. My opamp circuit may be overkill, but it does work well and provides a low source impedance voltage level to the ADC pin. |
| Siwastaja:
This is a long post and may contain some small inaccuracies, bear with it, but you really need to get the basics right before jumping into calculations. There is a lot to grok here. I think your solution is severely overengineered; nothing wrong here, I like to sometimes overengineer to learn more, but the risk here is that with such low-demanding use case, you won't see any difference in the final result: it will just work, regardless of what filter you use. For example, if you just accidentally wire input directly to output, completely bypassing the filter, the end result will very likely work just perfectly! First, you need to understand the ADC requirements. Your typical SAR ADC has a tiny little DC leakage, which is in tens of megaohms; or you can think about it as a tiny bias current. This is usually negligible, and even unspecified, I'm just mentioning it for the sake of completeness. More importantly, and this is the key, every time the ADC samples, the input signal is connected to the internal sampling capacitor for a very short time, called the sampling time. Of course, connecting the input signal to a capacitor suddenly, causes current only limited by the total resistance to flow. If you have almost zero resistance, a huge current flows, possibly causing multitude of problems (hence some amount of R is suggested by nctnico earlier). In the opposite case, if you have too much resistance, the sampling cap charges slowly; and because the sampling time is only so long, charging the cap remains unfinished when the sampling time is over. High-speed ADCs typically require input impedances as low as 20-30 ohms, because the sampling time can be as short as some tens to hundreds nanoseconds. If the PIC ADC is specified at 10kOhms as you say, it means it must use a very long (relatively speaking) sampling time internally; it's likely in several microseconds, see the datasheet. This makes your life easier, you can live with some impedance. Also note, the level of accuracy you require affects the input resistance you can tolerate. For example, assuming sampling capacitor of 20pF, and input resistance of 10kOhms, R*C = 0.2 µs. This means, after 0.2µs of sampling, the result would be 37% off. After 0.4µs, error is 13.5% After 0.6µs, error is 5%. After 1.0µs, error is 0.7%. Say, your sampling time is set to 1µs (by design of the ADC, or sometimes it's user-configurable). Is error of 0.7% acceptable? Sometimes 0.7% is more than good enough, hence 10k source resistance is just fine; sometimes 0.7% is abysmally poor result and you need something orders of magnitude better, hence use longer sampling time, or lower source impedance. The giveaway is, you need to make a distinction between DC resistance and AC impedance. Adding a 100nF capacitor to the ADC input, like I suggested, very clearly satisfies the 10kOhm impedance requirement. Let's play with the impedance for a minute: for a typical ceramic capacitor (ESR = 20mOhms), mounted close (10nH stray) to the input pin, the impedance at the relevant frequency (inverse of the sampling time, 1µs for now) would be Z = R_esr + L_esl + 1/(2*pi*f*C ) = 0.02ohms + 2*pi*1MHz*10nH + 1 / (2*pi*1MHz*100nF) = 0.02ohms + 0.06ohms + 1.5ohms Four orders of magnitude less than your allowed maximum of 10kOhms! Clearly, this impedance constraint is satisfied with the capacitor alone; then we only need to think about how we charge that (externally added) capacitor. But, it makes more sense to look this in the time domain in terms of current and charge, IMO, so let's get rid of the complex impedance equations: Say, you have a 100nF input cap and a 20pF sampling cap. When the sampling occurs, in worst case, you transfer approx. 20p/100n = 0.02% of the charge from the input cap to the sampling cap. So the input cap voltage changes just by 0.02%. This is the error you will see in the result! Now, the only requirement left is that the 100nF input caps needs to be able to replenish. This condition is relaxed when compared to not using input cap; with no input cap, the input signal needs to be able to fully charge the sampling cap during the sampling time; with the added input cap (Cin >> Csampl), the input signal still needs to supply the same amount of charge (it's only the ADC what's consuming it, after all), but has the whole time window between two samples to work with. For example, if sampling time is 1µs, and sampling rate is 1ksamples/second, the input signal has a massive 1ms time to charge the input capacitor, and that input capacitor takes over the job of charging the ADC sampling cap in just 1µs. But, seeing the ADC is specified to work acceptably (by some arbitrary definition by the PIC datasheet writers) even with such a high input impedance as 10kOhms, you may not even need the input capacitor! You may actually need nothing at all. But, I strongly recommend using the input capacitor for near-DC measurements. It's cheap (a BOM reuse, your bog standard 0402 power supply bypassing cap does fine), small, does good job at suppressing high-frequency noise at -6dB/oct, protects the input from ESD, and, allows you to use very large input resistances (up until the DC leakage / bias currents start to be a problem), say, 100kOhm to even 1MOhm is usually just fine, with only one condition: don't sample too often. This is the simplest and cheapest way to sense battery voltages, thermistors, and similar. I rephrase the external input capacitor once more because I have seen it cause confusion: a capacitor that is much larger than the sampling cap (Cin >> Csampl) removes the sampling time from the equations, and replaces it with the sampling interval. The latter is typically at least an order of magnitude longer, often many. So, the circuit reduces to something like a 10kOhm resistor for limiting current to protection diodes (internal for low-cost solution; external for added robustness; you may want to use two resistors in series, with the midpoint clamped with external protection diodes). This resistor does not cause any significant accuracy problem as you seem to think, as won't your 3k source resistance; the ADC input (with the 100nF input cap) consumes practically zero current, so no voltage drop is generated over those resistors (except when the clamp diodes are conducting due to overvoltage). The input impedance simply doesn't matter much; 10kOhm spec is already quite forgiving, and adding the input cap makes it matter even less (because now we are only interested in the average current the ADC consumes from the signal; not the peak current, which is handled by the input cap!) --- On the other hand, if you want to look at this as a generic data acquisition system, you should start by specifying your requirements first. Let's start with the required bandwidth. So, you are detecting key presses. Fine, what's the shortest keypress you want to reliably detect? Let's say 100ms. Say you want to debounce by detecting two consecutive settled values, so for that, the bandwidth should be enough to settle in less than 50ms. So, pass-band BW is in order of 20Hz, and at 20Hz, the amplitude should be close enough to detect the key correctly. Then let's look at the accuracy of converted numbers. This is catch-all that should include voltage errors due to component tolerances, all noise, ADC resolution, nonlinearities, etc. Let's see your table of values to be detected: Seek+ 20mV Seek- 800mV Vol+ 1440mV Vol- 2320mV NoPush 3240mV Let's calculate the "dead bands" between these expected values: Seek+ 20mV (780mV) Seek- 800mV (640mV) Vol+ 1440mV (880mV) Vol- 2320mV (920mV) NoPush 3240mV Now let's assign valid ranges for detection, consuming half of these deadbands, leaving half of them to detect "illegal" values: Seek+ from min_possible to 20mV+780mV/4 Seek- from 800mV-780mV/4 to 800mV+640mV/4 Vol+ from 1440mV-640mV/4 to 1440mV+880mV/4 Vol- from 2320mV-880mV/4 to 2320mV+920mV/4 NoPush from 3240mV-920mV/4 to max_possible Now what's the maximum allowable total error (due to all combined sources of error)? The smallest margin is between Seek- and Vol+, 640mV, which we divided by 4 to leave forbidden values inbetween. The maximum allowed error is thus +/-160mV, which is +/-4.8% of the (assumed) 3.3V signal and ADC range. Now, to add extra margin of safety, let's say we want +/-2% accuracy. This leads to the following conclusions: * 6 bits is enough resolution (each LSB is 1/64 = 1.56% of full range) * Signal-to-noise ratio needs to be 20*log10(2%) = -34dB Now, do you need low-pass filtering? Your signal clearly doesn't have intentional interfering components, it's basically a DC level defined by the push buttons. So outside the BW, there is just noise. How much? Now a key finding that they tell you in every signal processing 101 classroom is this, and this is true: analog filters become more expensive, larger, more costly, and more difficult (or impossible) to design taking component variations into account, the higher the order. This is why they tell you: use a simple/low-cost analog antialias filter, oversample, then implement a more steep (near to a brick-wall) filter in the digital domain. Of course, such complex way of thinking is not needed in your simple application, but the idea is the same. In your case, you won't need to implement a 512-tap FIR with a DSP, no, but you may want to look at the consecutive values in a loop to make sure you have steady values for 100ms, then react to the keypress. This basically is a digital low-pass filter tailored for the application. I don't know about the sample rate of your PIC ADC, or the processing power you have available, but let's say you really want that 20Hz BW. For that, the minimum Nyquist-defined sample rate is 40smps. I'm quite sure the PIC is able to sample at 1ksmps and run a simple filter at that frequency; with that, we are already at 25x oversampling, NICE. Now, the analog filter needs to be designed with the following parameters: Passband 0 .. 20 Hz Transition region 20Hz..500Hz Stopband 500Hz (half the sample rate)... inf The digital filter takes care of the loong transition region of the cheap analog filter. Still, any signal over 500Hz will alias, and if you are unlucky, for example, a 10005Hz signal aliases as 5Hz. But do you have extremely strong signals over 500Hz? I don't think so, there is only noise, and noise emissions are regulated by law (for very good reasons). So I propose using a first-order RC filter, because it's very low cost (< 1 cent), requires no power supply, has tiny PCB area (< 1mm^2 possible), ... and is more than good enough for such purpose - actually it's good enough for an order of magnitude more demanding use cases, such as measuring battery voltages to 0.5% accuracy at tens of Hz! Let's say we use 22kOhm series resistance, plus 3kOhm source resistance (= total 25kOhm), and a 100nF capacitor. Corner frequency (-3dB) is at 1/(2*pi * 25e3 ohm * 100e-9 F) = 64Hz Settling time to 1.8% accuracy (remember we specified 2%) is 3*tau = 3*R*C = 7.5ms. No problem detecting short keypresses! Attenuates noise (any unwanted signal) at 500Hz to 1/sqrt(1+(2*pi*500Hz*25e3Ohm*100e-9F)^2) = 12.6% Attenuates noise (any unwanted signal) at 5000Hz to 1/sqrt(1+(2*pi*5000Hz*25e3Ohm*100e-9F)^2) = 1.2% What's the worst possible case? We have a massive noise source at 501Hz singing somewhere, coupling into the wires. Now this would need to produce at least 1/12.6% * 160mV = 1.27V error signal so it would exceed our 160mV max error specification. At 5000Hz, the error signal (say, 5001Hz so it would alias at 1Hz) would need to be 1/1.2% * 160mV = 13.3V so it would pass through the 1st order RC filter badly enough. Connect a scope to your signal wires and measure what noise you see, while the car is running. I'm sure you won't see such huge noise sources. If you do, you likely need completely other ways of fixing and mitigating than increasing the order of analog LPF. Finally, I think this pseudocode describes what you need: --- Code: ---#define BUT_ILLEGAL -1 #define BUT_SEEKP 0 #define BUT_SEEKM 1 #define BUT_VOLP 2 #define BUT_VOLM 3 #define BUT_NOPUSH 4 #define ADC_BITS 8 #define ADC_CNT(mv) ((256*mv)/3300) //Seek+ from min_possible to 20mV+780mV/4 //Seek- from 800mV-780mV/4 to 800mV+640mV/4 //Vol+ from 1440mV-640mV/4 to 1440mV+880mV/4 //Vol- from 2320mV-880mV/4 to 2320mV+920mV/4 //NoPush from 3240mV-920mV/4 to max_possible static const uint8_t mins[5] = {ADC_CNT(0), ADC_CNT(800-780/4), ... }; // generate tables according to the previous comment static const uint8_t maxs[5] = {ADC_CNT(20+780/4), ...}; // run every 10ms or so: uint8_t cur_adc = input_adc(); int8_t cur_op = BUT_ILLEGAL; // -1 = illegal for(int i = 0; i<5; i++) { if(cur_adc > mins[i] && cur_adc < maxs[i]) { cur_op = i; break; } } static int8_t prev_op = BUT_ILLEGAL; static uint8_t stable_cnt = 0; if(prev_op == cur_op) { stable_cnt++; if(stable_cnt > 10) { button_is_actually_pressed(cur_op); } } else { stable_cnt = 0; } prev_op = cur_op; --- End code --- Hope this helps. |
| Navigation |
| Message Index |
| Previous page |