Jump to content
  • 0

pmodIA returning incoherent impedance values!


mbvalentin

Question

Hello to everyone.

First of all let me say that I already posted this question, by mistake, in the 'New users introduction' forum. As I don't know how to move it to another section I decided to start this new thread. In case the administrators consider it necessary I will delete my last post.

That said... I recently purchased an pmodIA board for a project we are conducting at work. The main goal is to obtain some resistivity vs frequency spectra for different objects as part of a object characterization problem involving Oil/Gas stuff.

I already read the guide that digilent guys provide (http://store.digilentinc.com/pmod-ia-impedance-analyzer/) and I found some C libraries for the AD5933 (https://github.com/analogdevicesinc/no-OS/blob/master/Pmods/PmodIA/AD5933.c    and   https://github.com/analogdevicesinc/no-OS/blob/master/drivers/AD5933/AD5933.c). 

I am using a Raspberry Pi 3 Model B to control & communicate with the pmodIA. I based my code on those C libraries I mentioned. In order to use i2c protocol with the raspberry pi I use wiringPi library (http://wiringpi.com/reference/i2c-library/).

In my code I have tested everything I've been able to, from all functionalities of the pmod: I get the temperature readings, set the frequency sweep params, make a freq. sweep measurement, etc. I have attached my code to this post (pmodia_test.tar.gz). All functionalities I tested seem to be okay, and everything seems to be working: I get the temperature, I can do a frequency sweep and if I connect the outputs of the pmod to an oscilloscope I can see the frequency sweeping (look at this video I recorded) 


Now, the thing is that even though everything seems to be WORKING, the result values I am getting back just make no sense AT ALL!!!

For calibration purposes I am using a 12k resistor. In my code I first set the gain (X1) and range (2Vpp), I configure the sweep params and start it, then I calculate the gainfactor using that 12k resistor (which I later use on all my calculations), and then I ask the user to change the impedance and put the one that they desire to measure.

On the main loop I simply do the frequency sweep, increasing the frequency at each step, calculate the impedance and put this value into an array (Z). I am also using gnuplot to display the results (the values obtained from the pmod are the exact same values that are being plotted using gnuplot, so this is not a display problem, as I checked this).


This is when things get weird. These are the results I got for the following tests:

The following curve is the IMPEDANCE response for the 12k resistor. At low frequencies there are quite a lot of spikes and high values. Notice that this curve is actually pretty close to the 'open circuit' ones from my first question in this post.
12kresistor.png.378b87df26fed49cdc5536aaf3fba0a2.png

The following curve is the MAGNITUDE for that same case. 

12kresistor_MAGNITUDE.png.a090233d5da9b60c88ddee48967e8d74.png

These spikes are caused by the lower value of Magnitude at low frequencies. 

Now, if I zoom to a range from 15kHz and 1MHz you can see that it actually displays something more reasonable (impedance going from 12k to almost 4k). 

12kresistor_IMPEDANCE_2.png.d1a80f672d747324ecff5e59a02bb890.png

 

I repeated the test but now using the 200mVpp output range instead of the 2000mVpp I was using, and the noise appeared back (see following curve).

12kresistor_200mVpp.png.1ce7cb996f7a25e26b5e95d56021ef85.png


Am I maybe saturating the ADC or something?

@D@n suggested me to check the part of my code that reads the data, because that noise or those readings might be related to the way I am handling with the signed/unsigned values stored in the ad5933 registers for the real/imaginary data. This is the part of my code that reads those registers:
 

/******************************************************************************
* @brief Calculate impedance.
*
* @param gainFactor - Gain factor calculated using a known impedance.
*
* @param freqFunction - Select Repeat Frequency Sweep.
*
* @return impedance.
******************************************************************************/
double AD5933_CalculateImpedance(double gainFactor,
								 char freqFunction)
{
	signed short realData   = 0;
	signed short imgData    = 0;
	double       magnitude  = 0;
	double       impedance  = 0;
	int          status     = 0;

	// Repeat frequency sweep with last set parameters
	AD5933_SetRegisterValue(AD5933_REG_CONTROL_HB,
							AD5933_CONTROL_FUNCTION(freqFunction)|
                            AD5933_CONTROL_RANGE(currentRange) | 
                            AD5933_CONTROL_PGA_GAIN(currentGain),
							1);



	// Wait for data received to be valid
	while((status & AD5933_STAT_DATA_VALID) == 0)
	{
		status = AD5933_GetRegisterValue(AD5933_REG_STATUS,1);
	}
	
	
	// Get real and imaginary reg parts
	signed short RealPart = 0;
	signed short ImagPart = 0;
	unsigned char byte          = 0;
	int tmp = 0;
	
	unsigned char registerAddress = AD5933_REG_REAL_DATA;
	for(byte = 0;byte < 2;byte ++)
	{
		// Read byte from specified registerAddress memory place
		tmp = wiringPiI2CReadReg8(i2cdevice,registerAddress);
		printf("\t\tReading from Register Address: 0x%02x...0x%02x\n",registerAddress,tmp);
		// Add this temporal value to our registerValue (remembering that
		// we are reading bytes that have location value, which means that
		// each measure we have we not only have to add it to the previous
		// register value but we also but do a bitwise shift (<< 8) by 1 byte
		RealPart = RealPart << 8;
		RealPart += tmp;
		// Update value from registerAddress to read next memory position byte
		registerAddress = registerAddress + 1;
	}
	
	registerAddress = AD5933_REG_IMAG_DATA;
	for(byte = 0;byte < 2;byte ++)
	{
		// Read byte from specified registerAddress memory place
		tmp = wiringPiI2CReadReg8(i2cdevice,registerAddress);
		printf("\t\tReading from Register Address: 0x%02x...0x%02x\n",registerAddress,tmp);
		// Add this temporal value to our registerValue (remembering that
		// we are reading bytes that have location value, which means that
		// each measure we have we not only have to add it to the previous
		// register value but we also but do a bitwise shift (<< 8) by 1 byte
		ImagPart = ImagPart << 8;
		ImagPart += tmp;
		// Update value from registerAddress to read next memory position byte
		registerAddress = registerAddress + 1;
	}
	
	
	magnitude = sqrt((RealPart * RealPart) + (ImagPart * ImagPart));
	
	printf("Z = %hi + %hi*i ... |Z| = %f\n",RealPart,ImagPart,magnitude);
	
	return magnitude;
	
}

For those who aren't familiar with the pmodIA, in order to calculate the impedance you have to read the values of 4 registers: 2 of them to read the real part of the measure (0x94 and 0x95) and the other 2 to read the imaginary part of the measure (0x96 and 0x97). These values are signed, as explained in the datasheet.  I realized that the original code I got from github stored these values into unsigned short variables and I changed that to signed short. Now the computation of the magnitude ( sqrt(Real² + Imag²) )  seems to be correct, as well as the values read from the registers.

Using this code I can calculate the gainFactor. For the 12k resistor I used, at a frequency of 3 kHz, I get:

Real = -79
Imag = -35
MAGNITUDE = 86.406021
gainFactor = (1/ (MAGNITUDE * CALIBRATION_IMPEDANCE) ) = (1/(86.406021 * 12000) ) = 9.64439e-7 


I use that gainFactor for all remaining impedance calculations. As an example of how my code seems to be working I copy/pasted the following lines (which are measurements of that 12k resistor at different frequencies). As explained before 0x94 & 0x95 registers contained the SIGNED value of the real part of the magnitude, while 0x96 & 0x97 registers contain the SIGNED value of the imaginary part of the magnitude. So, for instance, If I'm not mistaken,  0xffdf = -33, 0x0015 = 21.
 

		Reading from Register Address: 0x94...0xff
		Reading from Register Address: 0x95...0xdf
		Reading from Register Address: 0x96...0x00
		Reading from Register Address: 0x97...0x15
Z = -33 + 21*i ... |Z| = 39.115214
Impedance read: 3067.859955 ohms (@ 767500 Hz)
		Reading from Register Address: 0x94...0xff
		Reading from Register Address: 0x95...0xde
		Reading from Register Address: 0x96...0x00
		Reading from Register Address: 0x97...0x14
Z = -34 + 20*i ... |Z| = 39.446166
Impedance read: 3042.120759 ohms (@ 769000 Hz)
		Reading from Register Address: 0x94...0xff
		Reading from Register Address: 0x95...0xdb
		Reading from Register Address: 0x96...0x00
		Reading from Register Address: 0x97...0x11
Z = -37 + 17*i ... |Z| = 40.718546
Impedance read: 2947.060034 ohms (@ 770500 Hz)
		Reading from Register Address: 0x94...0xff
		Reading from Register Address: 0x95...0xdf
		Reading from Register Address: 0x96...0x00
		Reading from Register Address: 0x97...0x12
Z = -33 + 18*i ... |Z| = 37.589892
Impedance read: 3192.347538 ohms (@ 772000 Hz)
		Reading from Register Address: 0x94...0xff
		Reading from Register Address: 0x95...0xde
		Reading from Register Address: 0x96...0x00
		Reading from Register Address: 0x97...0x12
Z = -34 + 18*i ... |Z| = 38.470768
Impedance read: 3119.251469 ohms (@ 773500 Hz)
		Reading from Register Address: 0x94...0xff
		Reading from Register Address: 0x95...0xdc
		Reading from Register Address: 0x96...0x00
		Reading from Register Address: 0x97...0x11
Z = -36 + 17*i ... |Z| = 39.812058
Impedance read: 3014.162156 ohms (@ 775000 Hz)
		Reading from Register Address: 0x94...0xff
		Reading from Register Address: 0x95...0xde
		Reading from Register Address: 0x96...0x00
		Reading from Register Address: 0x97...0x10
Z = -34 + 16*i ... |Z| = 37.576588

Extra:

This is what happens when I put SEL to GND (same other conditions, and 12k resistor):
 

12kresistor_SELtoGND.png.f1b0dbc70646a8affd6d0c212b3de8c5.png



Some extra information: I am supplying 3V3 to the pmodIA through the raspberry pi. 

How is it possible that I am getting these results? Is there something wrong with my code? Is my board broken?? Is maybe my settling time for the sweep configuration not right?
Do I have to connect the SEL pin to GND or VCC?

I would really appreciate your help as I need to finish this experiment in, at least, 1 month.

Thank you so much for your attention, and let me know if you need more info.

Manu B. Valentin

Link to comment
Share on other sites

16 answers to this question

Recommended Posts

Hi @VishnuChittan,

Yes, that is the main drawback with the embedded AD5933 within the Pmod IA. The catch with the Pmod IA is that you already need to have some sort of idea of what impedance (or at  least a general range of impedance) in order to receive and interpret accurate data.

If you know (or can make an educated guess) what the approximate impedance will be, the next step would be to calculate if the output voltage range through the unknown impedance will saturate the ADC sampling this data, which as per the schematic is limited to a range between 0V and 3.0V. The equation used to figure out the gain applied (and what voltage would be presented to the ADC inputs) is as follows (as illustrated on page 18 of the AD5933 datasheet) :

Gain = Output Excitation Voltage * PGA Gain * Gain Setting Resistor Impedance / Z unknown

Where:

  • Gain (measured in volts) represents the peak to peak range applied to the ADC
  • Output Excitation Voltage is a register that is set in the AD5933 and can have a value of 0.2 volts, 0.4 volts, 1.0 volts, or 2.0 volts peak to peak. However, note that these values (listed on page 23) may actually be different as described on page 13, depending on what supply voltage you are using.
  • PGA Gain is register that is set in the AD5933 and can have a value of 1 or 5
  • Gain Setting Resistor Impedance is the selected resistor value via the header J2 (sel); if left alone (sel pulled logic high), this resistor value is 20 Ohms. If pulled to a logic low state, this resistor value is 100k ohms. Note that with resistors your actual resistance may vary depending on the resistor variance (I believe 1% or better resistors were used).
  • Z unknown (or predicted in this example) is the unknown impedance that is applied between the two SMA terminals (J3 and J4)

If the calculation yields a Gain value greater than 3V (or close to it), this means that any frequency sweep applied will saturate the input to the internal ADC and provide unhelpful and incorrect results. At the same time, you do not want too small of a result in volts because the 12-bit ADC will not be able to effectively measure any changes as each difference may or may not produce a change in the LSB.

If either of these things occur, either theoretically or in practice, you would likely want to change one of the settings (Output Excitation Voltage, PGA Gain, Gain Setting Resistor Impedance) to see what gain you would receive through the system.

Let me know if you have any more questions.

Thanks,
JColvin

Link to comment
Share on other sites

dear @JColvin,

Namaskaar!!

                        Hope you are doing well. While doing an experiment with PmodIA, I got a doubt. before calculating the impedance of an unknown sample, we are going to calculate the gain factor with known impedance values. My doubt is..... How this same gain factor value of the known impedance will be applicable for unknown samples too?  Please clarify my doubt.

Dhanyavaad.....

Link to comment
Share on other sites

Hi @VishnuChittan,

The primary document that I would follow is the AD5933 datasheet, specifically pages 17 and 18. The brief equation for the gain factor is as follows:

Gain Factor = (1 / Impedance) / Magnitude

Where the "Impedance" is the known Impedance that you apply during the calibration process and "Magnitude" is result when you take the square root of the sum of the real data squared and the imaginary data squared. The magnitude calculation is detailed more on page 17 in the Magnitude Calculation section.

Let me know if you have any questions about this.

Thanks,
JColvin

Link to comment
Share on other sites

 Hi @VishnuChittan,

I apologize for the delay. You do not need to calibrate on every sample, though you will need to calibrate on every range so that you have the correct gain factor for each calculation.

I have not worked with that particular library before, but when I tried it and it's associated example out, the code was able to compile and upload to my board successfully, but I was not able to do any further communication as the example sketch implied I would be able to; I kept sending commands over serial but never received any response. So I do not know if that library will work correctly or not.

Thanks,
JColvin

Link to comment
Share on other sites

hi @JColvin,

Dhanyavaad for your reply...

After seeing your reply, I am trying to measure the impedance for the frequencies from 10KHz to 100KHz with increment frequency value 10KHz.

My question is does it required to calibrate it for every sample or need to calibrate for every frequency range( i.e. for every 10KHz.)?

Now, my designed system asking the calibration Impedance for every increment frequency value, even for the same sample.

I am following the sample code attached here.AD5933.txt

I hope you understand my problem...

Dhanyavaad for your support.....

M Vishnu Chittan

Link to comment
Share on other sites

Hi @VishnuChittan,

I apologize for the long delay.

The short answer is that you would want to use calibration values that are within the impedance range that you are using (800 kOhm to 8 MOhm).

The longer answer is that the chip used in the Pmod IA (Analog Devices AD5933) is intended to be calibrated with much smaller frequency ranges; the example that they give in the datasheet for the two point calibration method is only 10 kHz. The reason for this small range (as described on page 17) is because the AD5933 has a finite frequency response. With a single point calibration scheme, you can see that a measured frequency of a 100 kOhm load between 55 kHz and 65 kHz ranges from 99.8 kOhm to 100.4 kOhms. With a much larger frequency range, even the two point calibration will produce a wide range of values that will inevitably be inaccurate.

One potential solution would be to get multiple gain factors for a set of ranges that are in the 10 kHz range and then try to predict the unknown impedance from each of those resulting formulas programmatically, but I don't know how you would determine which range is the most accurate. Additionally, the programmable frequency that is applied during calibration can only go to 100 kHz, so I do not believe the AD5933, and thus the Pmod IA, would be able to accurately measure samples with respect to frequency at 1 MHz.

Let me know if you have any questions about this.

Thanks,
JColvin

Link to comment
Share on other sites

Hi @VishnuChittan,

Here is the datasheet for the Pmod IA that will help with determining what values you will want to use during calibration. I attached the community RP3/Pmod IA project done by @mbvalentin below.  They have useful comments with the functions used to calibrate as well as in the test.c. I would also review the information posts by @mbvalentin  

thank you,  

Jon

 

BACKUP_WORKING_REPEAT.tar.gz

Link to comment
Share on other sites

Dear @JColvin,

Greetings!!!

Can I interface PmodIA with raspberry pi 3? 

Actually, I tried with chipkit mx3 to measure the impedances form around 8Mohm to 800Kohm.For these values how can I calibrate the PmodIA?I followed several documents related to calibration impedance. Please show some path to resolve my issues.....

 

Dhanyavaad...

Link to comment
Share on other sites

Hi @Renato,

I apologize for the delay.

Unfortunately, I do not think it will be possible to get the Pmod IA to reliably measure the low impedances as the quoted range of 100 Ohms to 10M Ohms was pulled from the AD5933 datasheet (link), so even if additional circuitry was added to make it work, I do not think it would be an accurate representation of the resulting waveform.

The resolution is a bit different. The datasheet for the impedance analyzer itself claims to have a resolution of 27 bits, correlating to less than 0.1 Hz (though not 1/100th of a Hz), but the ADC itself on the chip is only 12-bit so you won't achieve the same resolution since you will be limited to the 12 bits of resolution of whatever voltage range is being applied to the load.

So, while you could add an extra resistor in series with the load (which hopefully wouldn't change characteristics of the loudspeaker), but I don't think you will be able to get the resolution you are hoping for.

Let me know if you have any questions about this.

Thanks,
JColvin

Link to comment
Share on other sites

Hi @mbvalentin,

I'm looking for a board to measure, with arduino, low impedance in low frequencies (range from 2 to 200 Ohms, from 5Hz to 20kHz). It's a loudspeaker.

I checked Pmod IA (https://reference.digilentinc.com/reference/pmod/pmodia/start) but the range is from 100 Ohms to 10M Ohms. 

Will be enough if I add a 200 Ohms resistor in series with the load (loudspeaker)?

What is the resolution?

Will be nice if is possible works with 1/100th of Hertz and 1/100th of Ohms :-)

Can you give me a feedback if is possible use PMod IA to do this?

Thanks in advance...

Link to comment
Share on other sites

As @D@n mentioned, I was able to make the code work. I am actually very thankful for all the help he provided me through the process.

To be honest I am not entirely sure what I changed, exactly, but my guess is that the values were not read correctly from the registers of the AD5933. Here are some personal tips when using the pmodIA:

1) Be careful when picking the right combination of Feedback resistor (RFB), PGA Gain and Output Range voltage
Something very interesting that I found is that the actual implementation in the pmodIA is the one recommended by Analog Devices on the CN0217 Circuit note (take a look here: EVAL-CN0217-EB1Z .pdf). The only difference between this circuit and the circuit implemented on the pmodia is that the feedback resistor (RFB) in the pmodia can be selected by the user using the SEL pin (this is achieved by using an ADG849 digital switch, see datasheet here: http://www.analog.com/media/en/technical-documentation/data-sheets/ADG849.pdf). If SEL goes to GND the feedback resistor RFB is 100k. If SEL goes to VDD then RFB is 20k. 

Now, this RFB is important because choosing the wrong value might cause your ADC to saturate and, therefore, to give you a strange response. In page 19 of the circuit note I added before they give the formula to get the gain of the circuit. After some calculations I'd actually say that that formula is not the gain, but rather THE VOLTAGE input that arrives to the ADC (but I could be wrong about that, of course). Nevertheless YOU SHOULD BE CAREFUL ENOUGH TO PICK THE RIGHT COMBINATION OF EXCITATION RANGE VOLTAGE (2000mVpp,200mVpp,etc), THE RIGHT FEEDBACK RESISTOR (USING SEL PIN) AND THE RIGHT PGA GAIN (X1,X5) for the UNKNOWN IMPEDANCE THAT YOU ARE WILLING TO MEASURE. 

2) You must calibrate your system with a known impedance with a value close to the one you're willing to measure.
 know this might sound a little bit stupid but you have to know, at least, the range of impedance where you are going to work at. For instance, if you wanna measure an impedance that you guess might be around 180 kohm and 220kohm, then you must calibrate the system for those values. You can find an example of this at the circuit note I uploaded here, page 20, left column 3rd paragraph ("For example: assuming the following:..."). Do not calibrate your board with a 1MOhm resistor using a 300 kHz signal if you want to read impedances with a value close to a couple of hundred kohms and using a signal of 3 KHz...

3) Work in the narrowest bandwidth possible and, preferably, in mid-high frequencies.
The pmodIA is based in the CN0217 which is a "high precision impedance converter". High precision usually comes to a price which I would say that, in this case, is the bandwidth. In the document I uploaded, page 22, they say that "... The AD5933 is specified to a typical system accuracy of 0.5% (assuming the AD5933 system is calibrated correctly for the impedance range under test) within the frequency range of 1 kHz up to 100 kHz...".  However, all examples they give in the note uses a very narrow band (page 20, they give an example with a band between 30 kHz and 32 kHz, and they even say that you have to calibrate the board using a mid-point frequency of 31 kHz). This might have been one of the problems I had in my original code because I was using a 3 kHz signal with a 100k resistor to calibrate the system for a sweep between 3 kHz and 1 MHz. 

4) Make sure the i2c reading/writing procedure is okay and all your readings are what they are suppose to be
I used wiringPi library to communicate with the pmod in my code. Through the process @D@n and I discovered that wiringpi's i2cReadReg16 function was not working properly to read 2byte words from successive registers (like 0x94 and 0x95, for instance), so I had to stick to a double reading of 8 bits rather than try to read these measures at once. 


Anyway, here's my code (BACKUP_WORKING_REPEAT.tar.gz). I am still working on it but at least it might be helpful for anyone who wants to use Raspberry Pi to communicate with the pmodIA or directly to the AD5933.

Hope it helps.

Manu B. V.

Link to comment
Share on other sites

To those on the forum,

@mbvalentin was able to get the interface working for him today.  There were two basic things we did to get it going: one was to be aware of what standard deviation would be created by the formula.  In particular, when dividing by numbers near to (or equal to) zero, the variance in the part gets quite high.  The second thing was to use a potentiometer (IIRC) to walk through the various responses to the PmodIA.

I'll let him comment more (or correct the above) if he'd like,

Dan

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...