Post Go back to editing

# Problem in measuring impedance at lower frequency from 10 Hz to 1k Hz using AD5933

Hello everyone, I am developing an impedance measurement system using AD5933 with a microcontroller. I can measure impedance from 47 ohms to several mega ohms from frequency range 5k to 100k Hz. Now I want to measure impedance from frequency range 10 Hz to 4k Hz. I have uploaded my AFE picture. I know there are many threads related to lower frequency excitation, I have gone through them but I did not get an appropriate idea.

I have uploaded a picture below. According to my understanding after going through this table, we can measure impedance at a low-frequencies by simply giving an external clock to AD5933 pin. I have tried but it's just working for 16Mhz and 4Mhz external oscillator clock. For lower frequencies from 10Hz to 1K Hz how can we measure impedance, do we need any calculation for settling cycle register?

Parents
• Quite an elaborate AFE you got there... The suspect would be the circuit R8R9R10C3 that acts as a low-pass filter with a time constant (R8||R9||R10)*C3 = 1.41630901288kOhm*1μF = 1.4 ms, so operating frequencies lower than a few KHz start noticeably leaking through. The suggestion would be to increase the resistors R8, R9, R10 (and, of course, R13 to keep R13/R10 ratio the same) or C3 or all the above. And prepare for long sweep duration.

If your current number of settling cycles works for your measurements at high MCLK, there should be not need to change it at lower MCLK.

• Thank you for your reply, I got this circuit from chabowski paper [1],  In this paper page num. 16 it is discussed that (ICA and ICB are for DC bias canceller. the voltage detectors are averaged on R8 and R9 and its correspond to DC bias voltage.

I think it's not an AFE problem because now I am trying to measure lower frequencies without AFE. I have measured 20kohm resistor with RFB 10kohm, it gives correct measurement from frequency sweep (5k-100k) by using 16Mhz external clock (settling cycle 0x64) and from 1khz to 5khz by using the 4Mhz external clock (settling cycle=0x0F), but when I am connecting 2Mhz external clock it acts as I have shown in video (running infinitely). but if I change the settling cycle from 0x0x0F to 0x05 it gives the result that I have shown in the image (not correct), I have measured 20kohm with 10kohm RFB.

1SIMPLE WIDE FREQUENCY RANGE IMPEDANCE METER BASED ON AD5933 INTEGRATED CIRCUIT

Konrad Chabowski, Tomasz Piasecki, Andrzej Dzierka, Karol Nitsch

Metrology & Measurement System, Vol. XXII (2015), No. 1, pp. 13–24.

• the formula Rcal = 1/3 * (Zmin + Zmax) is not practical

If you are not using demo software, are you controlling the Demo board from your Arduino Blue Pill?

I am confused with the "Default" number of settling time cycles

There is no default number of settling cycles, the demo software defaults it to be 15, but there is no particular reason for that. This is simply the number of excitation voltage sine wave periods the chip outputs after switching to the next frequency in the course of sweep before it starts sampling the Vadc. As long as it is not zero, it should not matter much for your experiments with non-resonant circuits, which most biosensors are. Setting Number of Settling Cycles at 1 should be OK for your measurements and would keep your sweep time short.
If your Z is a resonant circuit, shifting from one frequency to the next causes beating in the current passing through between the resonant frequency ωand the excitation frequency. This beating takes time to pass for the current sine wave at the new excitation frequency no longer be distorted. If the quality factor of Z is Q, the settling time constant can be estimated as τ =2 Q / ω0 and, similarly to the settling we discussed, it is good idea to wait 7-10 times this time constant to make sure the beatings do not affect the measurements.

my system is driven using the library I shared before https://github.com/mjmeli/arduino-ad5933

The AD5933.cpp contains the method "bool AD5933::setSettlingCycles(int time)", but it is not called from the ad5933-test.ino, so this Number of Settling Cycles is not initialised. Datasheet does not specify what value the registers assume upon the chip power-up. When using this library it would make sense to stick with the diagram on Fig. 28, p. 22 of the datasheet, which does require for the Number of Settling Cycles to be initialized.

Collected Results

Big swings in the data at 3-4 points at the lower frequency end are likely from the systematic error from the built-in "DFT" - will require even lower MCLK to eliminate. At the higher frequencies, something is happening at 5KHz, is this the frequency where you are switching from 16MHz to 2MHz MCLK? Not yet clear what it is, but it causes a noticeable step in the data from evaluation board as well as from the setup with two different capacitor values, as if the control binary words for the frequency with the new MCLK are not calculated quite correctly. Could be a number of other issues - we will need to look at it further.
It sounds like you use different Rfb and Rcal for each frequency range (partition), how do you switch Rfb as you sweep across entire frequency range over several partitions? Just to see if the switching between the ranges causes discontinuities in the data, could you connect the Rfb and Rcal you are using above 5KHz (230 and 150 Ohm), perform the entire sweep same way as you did collecting this data and post raw Re and Im values you are getting from the registers? And then the same raw Re and Im values with your R||C network?

the formula Rcal = 1/3 * (Zmin + Zmax) is not practical

Not only it is not practical, it can lead to wrong calibration. For example, if someone is trying to measure an impedance, which does not change much, so that Zmax ≈ Zmin, this formula would suggest to use Rcal = 2/3 * Zmin, which would guarantee the Vadc clipping, faulty calibration and the user endlessly puzzling over incorrect measurement results.

• Hi  ,

If you are not using demo software, are you controlling the Demo board from your Arduino Blue Pill?

Yes, I directly control the demo board via the two small I2C via holes on the board using my Arduino Blue Pill.

If your Z is a resonant circuit, shifting from one frequency to the next causes beating in the current passing through between the resonant frequency ωand the excitation frequency. This beating takes time to pass for the current sine wave at the new excitation frequency no longer be distorted. If the quality factor of Z is Q, the settling time constant can be estimated as τ =2 Q / ω0 and, similarly to the settling we discussed, it is good idea to wait 7-10 times this time constant to make sure the beatings do not affect the measurements.

Yes, my biosensor is actually a resonant circuit. We usually analysed it using Randles Circuit, which can be viewed as R-(R||C). As my current Z unknown is 1000kohm||0.1uF, the time constant τ=RC is 100us and the recommended settling time is 100us * (7 to 10 ) = 0.7ms to 1ms. May I know if this is correct please?

The AD5933.cpp contains the method "bool AD5933::setSettlingCycles(int time)", but it is not called from the ad5933-test.ino, so this Number of Settling Cycles is not initialised. Datasheet does not specify what value the registers assume upon the chip power-up. When using this library it would make sense to stick with the diagram on Fig. 28, p. 22 of the datasheet, which does require for the Number of Settling Cycles to be initialized.

I have figured out why I could directly run frequency sweep without initialising the number of settling cycles. As the number of settling cycles will not be reset automatically, the number I am currently using is the number that I accidentally set when I was testing the commands in the library last time. I have experimented a few numbers and number>60 can give me similar results that I sent you above. When the number is <30, e.g. 15, the measured points aren't even lining on the curve, which I have no idea why. Below is the screenshot of my initialisation:-

where I have modified setStartFrequency and setIncrementFrequency with additional argument CLK so that I can keep changing the MCLK value (ECLK stands for 'external clock').

Big swings in the data at 3-4 points at the lower frequency end are likely from the systematic error from the built-in "DFT" - will require even lower MCLK to eliminate. At the higher frequencies, something is happening at 5KHz, is this the frequency where you are switching from 16MHz to 2MHz MCLK? Not yet clear what it is, but it causes a noticeable step in the data from evaluation board as well as from the setup with two different capacitor values, as if the control binary words for the frequency with the new MCLK are not calculated quite correctly. Could be a number of other issues - we will need to look at it further.

I have tried with MCLK 1MHz. As you expected, I am able to measure down to around 500Hz to 600Hz correctly (which I assume it's correct as it follows the trend). For the discontinuities at the higher frequencies, I believe they are caused by the change of MCLK as well as the calibration resistance. Regarding the calibration method you suggested, I think my method is similar to yours but I calculated the gain factor and system phase directly instead of using the complex gain factor. As my calibration method worked with the demo board before, may I know if it is necessary for me to switch to your method?

Besides, I just realised my start frequency code might be calculated wrongly. Although the results I sent you above may seem to be correct at the moment with my current setup, I only initialised the correct MCLK value in my new setStartFrequency function while doing calibration, but I have forgot to specify the correct MCLK value while performing frequency sweep to my R||C circuit. The oddest part is that after I amended the correct MCLK value in setStartFrequency for my frequency sweep, the results have gone crazy. Something is definitely going wrong in my code. I will check again and get back to you.

It sounds like you use different Rfb and Rcal for each frequency range (partition), how do you switch Rfb as you sweep across entire frequency range over several partitions? Just to see if the switching between the ranges causes discontinuities in the data, could you connect the Rfb and Rcal you are using above 5KHz (230 and 150 Ohm), perform the entire sweep same way as you did collecting this data and post raw Re and Im values you are getting from the registers? And then the same raw Re and Im values with your R||C network?

Actually I plan to automate the Rfb-switching process using a MUX. However, as I am still experimenting on different partitions, I am changing the Rfb and Rcal manually at the moment. Basically, the data I sent you above are the combined version of different measurements instead of an one-shot measurement. Fortunately, I still keep data of each partition before combining as well as their raw Re and Im values from the register. Please see the attached excel file. Thank you.

Besides, may I know if there is any way to calculate the required MCLK for each excitation frequency please? Based on my current results, the table below from the technical note does not seem to be accurate. I am currently trying to measure frequency down to 10Hz, basically the frequency below 500Hz are all wrong although I have changed the MCLK to below 250kHz. The system would even hang when MCLK<250kHz so I am forced to reduce the number of settling cycles, in which the results have become even worse. Would it be the problem of the software bug about the start frequency code I mentioned above? As there are too many uncertainties at the moment, could you give me some advice for debugging please?

As I am sweeping across wide frequency, I have made a few partitions following the recommended MCLKs as shown below:

Thank you so much for your help. I really appreciate it.

• I directly control the demo board via the two small I2C via holes on the board using my Arduino Blue Pill

R-(R||C)

No, it is not resonant, the equivalent circuit would need to contain and inductance and capacitance and the resistance (loss) to be low enough for the Q-factor to be more then 1 to observe any resonant behavior. So, Number of Settling Cycles should not be a factor in your measurements, yet apparently it somehow is - needs further debugging.

I assume it's correct as it follows the trend)

Yes, with complex circuits it is always good idea to check if the collected data follows expected response without jumps or discontinuities.

I calculated the gain factor and system phase directly

Absolutely nothing wrong with it, it is just you need to track two values: gain amplitude and system phase and remember that gain amplitude is multiplicative with the impedance absolute value and system phase is additive to the impedance phase. With complex arithmetic you are dealing with singular complex values and only multiplicative relationship that takes care of amplitude and phase automatically, more compact. Again, no need to switch if complex arithmetic does not look appealing.

the measured points aren't even lining on the curve, which I have no idea why

Likewise, it is really puzzling - the Number of Settling Cycles should not affect your measurements in any significant way. The way the library example you are following initializes the chip, however, is far from optimal. If any of the 7 functions that are called within the logical sum in the If statement fails, the software reports failure, but there is no way to see which of the 7 functions failed specifically. Also, the logical sum does not depend on the order of the terms, so nothing prevents the compiler from calling the functions in the sum in arbitrary order, not necessarily in the order they are in the If statement. If this happens, the initialization order may be wrong, so I would suggest to break this If statement ito 7 individual If statements in the sequence prescribed by the diagram on Fig. 28, p. 22 of the datasheet.
Same applies to the return statement in your code example, returning the logical sum of functions sending the three bytes may or may not keep the byte sequence the same as written in the statement, so it would be safer calling sendByte functions sequentially.
Not that important, but the increment code could be made a bit more accurate by using round():   long freqx = round((increment / (ECLK / 4.0)) * pow(2, 27));

if there is any way to calculate the required MCLK for each excitation frequency please?

At  MCLK 16 MHz the systematic "DSP" error becomes noticeable below 10 KHz, but as "noticeable" it is somewhat subjective, may be down 5 KHz is still OK. This frequency threshold is proportional to MCLK, so if one wants to place this threshold at 10Hz, then MCLK = (10Hz/5KHz) * 16MHz = 32KHz. In reality the "DSP" error is really a function of the Frequency Code rather then the MCLK frequency - that is the reason for reducing MCLK to get accurate data at low frequencies.

The system would even hang when MCLK<250kHz so I am forced to reduce the number of settling cycles,

Not sure if the settling cycles is likely the problem. Some folks in this forum reported the I2C communication becoming unreliable at low MCLK frequencies (although not clear what might be causing it as I2C communication is normally clocked by the SCL from the master) and the remedy was reducing the I2C speed in microcontroller settings.

Would it be the problem of the software bug about the start frequency code

Yes, anything involving frequency codes could cause a problem. Once you have fixed it feel free to post your code via Insert -> </>Code, although remote debugging is typically ineffective.

• XLSX

You have probably noticed that the data from the breadboard is about the same as the data from the Evaluation board about 50% of the time and other 50% - it is off quite substantially. It looks like you are using the same code to collect the data from both boards, but is the microcontroller physically the same or are there two different boards with the same microcontroller type? This could be indicative of I2C communication errors that are not caught by the Arduino Wire functions. Does your breadboard setup have the same pullup resistors 2.2k on SCL and SDA lines as the Evaluation board? Somehow we need to troubleshoot the breadboard setup.

• Hi  , I was using 10kohm pull up resistor initially as I have multiple slxvx (sorry I need to censor the word due to AD "Word Matters") devices on the bus. I am not sure how to calculate the correct pull up resistance when there are multiple slxvx devices on the bus, so I have chosen 10kohm as the safest option. Really thanks a lot for pointing out this problem.

I have changed the pull up resistance back to 2.2kohm and added the 2.5s settling time before frequency sweep (for both calibration and actual measurement). I have also ensured that the modified setStartFrequency() is called correctly with respect to the MCLK used. I can see some improvements in the results as shown below. The frequency sweep from 5kHz to 10kHz is very good, but the gap starts appearing again for 400Hz-5kHz sweep. Besides, I managed to set the settling cycles to 15 (tried with 30, 60 and 255 as well, the results are very consistent) for all my partitions and it did not cause any system hang at all, even when I was scanning down to 10Hz. However, the gap is still very big, and there is no continuation for freq <400Hz. Was wondering if this could be the problem of the breadboard or there is anything I can do to reduce the error?

Besides, please see the attachment below for the newly collected data.

XLSX

I will proceed to separate all the initialisation and sendByte functions, and also use round() for my increment code. Will update soon. Please let me know if there is anything I can do to improve my system.

Really thanks a lot for your help.

• I am not sure how to calculate the correct pull up resistance

Nobody seems to know, the rule of thumb is to start with 10k or 4.7k and go lower if the bus is getting longer and number of devices increases. For some reason your microcontroller seems to like 2.2k installed on the Eval board.
You may ignore the attempts to censor your referring to "slave" devices on the bus - there should be an option to disregard the warning by pushing "Post" button, do you get this "Post" button in the popup dialog?

but the gap starts appearing again

To debug this discontinuity issue, can you just calibrate with the lowest Rfb (230 Ω) while sweeping all the way down to 10 Hz while changing MCLK only between to your partitions, but not the Rfb and Rcal? And then sweep the same way with Rcal or some known resistor R > Rcal and see if there still going to be any discontinuities? And then do the same with your R||C network? And post the Exel here? This should help us to see if the discontinuities are caused by switching between Rfb-s and Rcal-s and not by the software calculating Frequency Codes for different MCLKs incorrectly?  (BTW round() could be used in all Code calculations, not just the increment, although not that important)

XLSX

These are calibration data - all seems to be in order.
The cut-off frequency with C of 0.1 uF is about 64 Hz, which somewhat reduces the effective excitation voltage when you sweep below 100 Hz making measurements slightly suboptimal, but this does not explain the discontinuities and calibration should still lead to correct impedance values.

Another thing is the accuracy of components you are using for calibration and R||C network: the capacitors are known to deviate from their nominal values by up to 10% or more. What are the accuracy of the resistors you are using? It would make sense to try getting some high-precision resistors with 0.1% or better tolerance (avoid the wirewound ones).

I managed to set the settling cycles to 15

It should be safe to try setting this number at 1 to reduce the duration of your sweep, especially at lower end of your spectrum.

• Hi  ,

To debug this discontinuity issue, can you just calibrate with the lowest Rfb (230 Ω) while sweeping all the way down to 10 Hz while changing MCLK only between to your partitions, but not the Rfb and Rcal? And then sweep the same way with Rcal or some known resistor R > Rcal and see if there still going to be any discontinuities?

I have tried with 150ohm, 240ohm and 1kohm||0.1uF from 10Hz to 10kHz with Rfb=230ohm and Rcal=150ohm. I have collected the results twice for each target. Please see the attached excel file for the collected results. For 150ohm, everything seems fine. However, for 240ohm, the error is quite big and the discontinuities are very obvious. For 1kohm||0.1uF, the results are very off for frequency < 600Hz.

XLSX

However, I am not quite sure whether I had performed the frequency sweep correctly as you expected. I basically just combined the partitions together using a for loop so that the data for each partition were collected automatically (previously I would collected the data for each partition first and then combined them together in excel manually). In the beginning of each partition, I have configured the start frequency, num of increments and freq of increment, and also provided a 2.5 settling time. May I know if I have misunderstood what you meant regarding the full sweep?

Or you would actually want me to perform the frequency sweep with only one start frequency and then adjusted the MCLK only when the frequency reaches the threshold (e.g while sweeping from 400Hz to 10kHz, MCLK is changed from 1MHz to 16.776MHz when frequency reaches 5kHz)?

The cut-off frequency with C of 0.1 uF is about 64 Hz, which somewhat reduces the effective excitation voltage when you sweep below 100 Hz making measurements slightly suboptimal, but this does not explain the discontinuities and calibration should still lead to correct impedance values.

I am so sorry. It's a typo in the attached results (Results-20240127). I used 10uF instead of 0.1uF, so the cutoff is actually 0.64Hz. Really sorry about it.

Another thing is the accuracy of components you are using for calibration and R||C network: the capacitors are known to deviate from their nominal values by up to 10% or more. What are the accuracy of the resistors you are using? It would make sense to try getting some high-precision resistors with 0.1% or better tolerance (avoid the wirewound ones).

Noted on this. I have ordered the 0.1% tolerance resistors. Will try it out when I receive them.

It should be safe to try setting this number at 1 to reduce the duration of your sweep, especially at lower end of your spectrum.

I am not sure why but the results were inconsistent when I set it to 1. When the number of settling cycles is 15, the results are very consistent.

Do you think I should try to calibrate the system manually for each partition (as the results I collected before seem quite consistent with the Rfb and Rcal I chose for each partition) and combine them together in a CSV file? I  will then perform a full frequency sweep on my RC based on the calibrated data from CSV file and switch between different values of Rfb using a MUX as proposed in the schematic before. Or Do you think I should continue to debug the system?

• Thanks for posting, very helpful and you did it great. Your system seems to function the way it is supposed to, except with the Rfb = 230 and Rcal = 150 there may be a little bit of clipping present and that likely throws the Z = 240 measurements (when there is no clipping) a bit off - down to 231-232 or so. The suspect is the section in your datasheet, where you estimate Rfb based on Zmin = 150:

 min|Z| max|Z| RFB RCAL RFB_Actual RCAL_Actual 150 150 219.6969697 150 230 150

The formula we discussed earlier calls for Rfb to be less then or equal to the value from the formula, which you calculated at 219.6969697, so it would be safer to pick Rfb of 210 or even 200 to be sure that there is no clipping, the 230 is too risky. It would make sense to repeat this same experiment with lower Rfb and see if the Z = 240 results improve. Something else still could be an issue, later we will probably need to look at the code.

I used 10uF instead of 0.1uF

When the number of settling cycles is 15, the results are very consistent.

Let's keep it this way for now, might need to revisit it once basic functionality is in place. It should not affect the measurements at all, could be something in the code.

• Hi  , I have completed the full measurement (automated each partition with respect to their Rcal and Rfb). First, I collected the calibration data (phases and gain factors with respect to each frequency) based on each partition, and then I stored them as arrays in the code and perform the frequency sweep. Below are the averaged measurements with respect to the partitions and different number of settling cycles

Please see the attached below for more results. I have corrected the Rcal value as well. However, I still have no clue why the errors are still so high. Could you give me any suggestion to debug please? My 0.1% tolerance resistors are arriving soon as well. Will try with them and update soon.
XLSX
Btw, as Rfb is chosen based on Zmin to ensure that the ADC won't saturate and Rcal needs to be > Zmin, may I know if there is anyway to calculate the maximum impedance that a certain combination of Rfb and Rcal can measure accurately with respect to specific sweep frequency? Theoretically, the maximum measurable impedance should be infinite right?

Thank you.

• why the errors are still so high

If the software calculates all frequency codes correctly, you are likely running into the DFT systematic errors. To reduce these errors is it necessary ro reduce MCLK below what you are using for your partitions:
10000 - 5000 Hz  MCLK of 16 MHz is barely OK, lowering it down to 8 MHz would be better
5000 - 400 Hz       MCLK at 640 KHz
400 - 200 Hz         MCLK at 320 KHz
200 - 100 Hz         MCLK at 160 KHz
100 - 10 Hz           MCLK at 16 KHz

I collected the calibration data (phases and gain factors with respect to each frequency) based on each partition, and then I stored them as arrays in the code

Could you please put these calibration data arrays along with the Re(Reg) and Im(Reg) from which you calculated gain and system phase and also the resistor values used as Rfb and Rcal for each and partition(s) in to Excel and post it along with the measurements data?

Theoretically, the maximum measurable impedance should be infinite right?

The maximum theoretical measurable impedance is always infinity as is the case when no Z is connected to the circuit. In practice, if nothing is connected to the circuit, the AD5933 output registers show some fluctuating small values resulting from everpresent electronic noise and interference (typically ±5-10 counts), which, with the calibrated gain, can be formally calculated into a noisy "Zmax" (except on occasions when both registers happen to contain exactly 0), but it is is not all that meaningful.

• why the errors are still so high

If the software calculates all frequency codes correctly, you are likely running into the DFT systematic errors. To reduce these errors is it necessary ro reduce MCLK below what you are using for your partitions:
10000 - 5000 Hz  MCLK of 16 MHz is barely OK, lowering it down to 8 MHz would be better
5000 - 400 Hz       MCLK at 640 KHz
400 - 200 Hz         MCLK at 320 KHz
200 - 100 Hz         MCLK at 160 KHz
100 - 10 Hz           MCLK at 16 KHz

I collected the calibration data (phases and gain factors with respect to each frequency) based on each partition, and then I stored them as arrays in the code

Could you please put these calibration data arrays along with the Re(Reg) and Im(Reg) from which you calculated gain and system phase and also the resistor values used as Rfb and Rcal for each and partition(s) in to Excel and post it along with the measurements data?

Theoretically, the maximum measurable impedance should be infinite right?

The maximum theoretical measurable impedance is always infinity as is the case when no Z is connected to the circuit. In practice, if nothing is connected to the circuit, the AD5933 output registers show some fluctuating small values resulting from everpresent electronic noise and interference (typically ±5-10 counts), which, with the calibrated gain, can be formally calculated into a noisy "Zmax" (except on occasions when both registers happen to contain exactly 0), but it is is not all that meaningful.

Children
No Data