I've been trying to replicate a 2015 paper that uses electrical impedance tomography to map a cross-section of a hand. They use the AD5933 bio-impedance analyzer.
On page 3 of the paper, they say they could achieve a sample speed of 3ms per sample, but performing a simple, single frequency sweep with the same chip takes me over 90 ms on average.
I'm using modified code from a different project for the AD5933 and Arduino. I've included the parts I think are relevant (although I understand usually the code contained in a post isn't always the offending segment, I'm shortening it to not make the question too long).
//ALL CAPS VARIABLES ARE SET TO THE HEX VALUES SPECIFIED IN THE DATASHEET (AFTER PAGE 23)
//PROGRAMS THE REGISTERS BEFORE A SWEEP. TAKES AROUND 25ms, BUT ONLY NEEDS TO BE PERFORMED ONCE PER FRAME
void programReg() {
// Set Range 1, PGA gain 1
writeData(CTRL_REG,0x01);
// Set settling cycles
writeData(NUM_SCYCLES_R1, 0x07);
writeData(NUM_SCYCLES_R2, 0xFF);
// Start frequency of 1kHz
writeData(START_FREQ_R1, getFrequency(start_freq,1));
writeData(START_FREQ_R2, getFrequency(start_freq,2));
writeData(START_FREQ_R3, getFrequency(start_freq,3));
// Increment by 1 kHz
writeData(FREG_INCRE_R1, getFrequency(incre_freq,1));
writeData(FREG_INCRE_R2, getFrequency(incre_freq,2));
writeData(FREG_INCRE_R3, getFrequency(incre_freq,3));
// Points in frequency sweep (100), max 511
writeData(NUM_INCRE_R1, (incre_num & 0x001F00)>>0x08 );
writeData(NUM_INCRE_R2, (incre_num & 0x0000FF));
}
//CODE WHERE THE ACTUAL SWEEP IS PERFORMED
void runSweep() {
Serial.print("0: ");
Serial.println(micros()-t);
short re;
short img;
double freq;
double mag;
double phase;
double gain;
double impedance;
double tot=0;
double avg;
double a, b, c;
int i = 0;
int j = 0;
int flag = 0;
boolean w_f;
programReg();
// 1. Standby '10110000' Mask D8-10 of avoid tampering with gains
writeData(CTRL_REG,(readData(CTRL_REG) & 0x07) | 0xB0);
// 2. Initialize sweep
writeData(CTRL_REG,(readData(CTRL_REG) & 0x07) | 0x10);
// 3. Start sweep
writeData(CTRL_REG,(readData(CTRL_REG) & 0x07) | 0x20);
w_f = (readData(STATUS_REG) & 0x07) < 4 ; //Checks if the frequency sweep is not complete
Serial.print("1: ");
Serial.println(micros()-t);
while (w_f) {
flag = readData(STATUS_REG)& 2; //This is true if there is valid data in the register (DS, pg. 26)
Serial.print("2: ");
Serial.println(micros()-t);
while (flag != 2) {
delay(3);
flag = readData(STATUS_REG)& 2;
Serial.print("2.1: ");
Serial.println(micros()-t);
if (flag == 2) {
byte R1 = readData(RE_DATA_R1);
byte R2 = readData(RE_DATA_R2);
re = (R1 << 8) | R2;
R1 = readData(IMG_DATA_R1);
R2 = readData(IMG_DATA_R2);
img = (R1 << 8) | R2;
freq = start_freq + i*incre_freq;
mag = sqrt(pow(double(re),2)+pow(double(img),2));
Serial.print("3: ");
Serial.println(micros()-t);
Serial.print(" Resistance: ");
Serial.print(re);
Serial.print(",");
Serial.print(" Reactance: ");
Serial.print(img);
// break; //TODO: for single run, remove after debugging
//Increment frequency
w_f = (readData(STATUS_REG) & 0x07) < 4 ;
if (w_f) {
writeData(CTRL_REG,(readData(CTRL_REG) & 0x07) | 0x30);
}
Serial.print("4: ");
Serial.println(micros()-t);
}
}
// Power down
// writeData(CTRL_REG,0xA0);
}
writeData(CTRL_REG,(readData(CTRL_REG) & 0x07) | 0xA0);
}
I have timing markers on the runSweep()
function that return this (numbers in microseconds from micros()
):
1: 25096.00
2: 27900.00
2.1: 33724.00
2.1: 39572.00
2.1: 45412.00
2.1: 51256.00
2.1: 57104.00
2.1: 62944.00
2.1: 68792.00
2.1: 74644.00
2.1: 80488.00
3: 90012.00
Resistance: -106, Reactance: 301, Impedence: 37267.40
4: 97448.00
2: 100260.00
2.1: 106132.00
2.1: 112020.00
2.1: 117912.00
2.1: 123808.00
2.1: 129712.00
2.1: 135600.00
2.1: 141468.00
2.1: 147340.00
2.1: 153212.00
3: 162772.00
Resistance: -146, Reactance: 418, Impedence: 26873.24
4: 166912.00
Last: 170948.00
My question is: How do I decrease the time it takes for a sweep to be performed?
I've tried: setting the speed of the Wire.h
library to 400000Hz (the fastest timing), and skipping the flag check step after a 5 ms delay (led to useless data). On the hardware side, I tried replacing the chip, to no avail. I've run out of ideas, so any help is greatly appreciated.
Edit: In another function which samples the entire frame of electrode pairs, I use the repeat frequency command, but this doesn't cause a noticeable speed boost.
Edit 2: I've added an answer as a community wiki. The problem was in programReg() specifically the Set settling cycles
portion.