Xerrorable
Member
Hi everyone,
First let me say that I am in no shape or form a professional electrical engineer (I am a chemist-turned-electronics-hobbyist).
I am working on a pcb project where I try to make my own scalar network analyzer to measure quartz crystal resonances.
It looks similar to the design of Brett Killion (https://hackaday.com/2016/03/06/arduino-rf-network-analyzer/)
In short I am using an AD9851 DDS chip to generate my sine waves which are then passed through a LPF(70MHz cut-off) onto a buffer amplifier. This is then sent through a quartz crystal and the signal coming out at the other end is analyzed by a logarithmic amplifier. This outputs a certain voltage based on the envelope of the sine at its input. The output is again buffered and read by an analog pin of the microcontroller. The microcontroller that I use is the Teensy 4.0 and it is communicating over USB with a Python DAQ script using PySerial. Thus far I have been able to get quite nice results. However, I am now looking into speeding up the measurements to get a high time resolution.
I have posted on this forum before about the slow speed of data transfer likely caused by using the PySerial library. Simply put, I was using a too high frequency resolution (1Hz) for my measurements (requiring tons of data points per frequency sweep). I have since changed tactics and spend more of the computing power on the Teensy side. I use less data points per sweep (~10Hz resolution) and I fit a spline function to this result with much higher resolution on the Python side. To be able to get a good enough fit (1Hz resolution) I must average the 12 bit ADC measurement values at least ~30 times per frequency and do this for roughly 500 frequencies. I have confirmed that I am now mostly waiting on the Teensy by checking the available bytes in the PySerial buffer (it is mostly 0 and sometimes 2 when the Teensy sends the measurement data of a point).
(Part of the Teensy code is attached below, basic function is receiving a string from the Python script about the frequency sweep, converting this to a frequency range the Teensy can work with and using a serial Set_Frequency() function described by Analog Devices in their datasheet, measuring analogRead() at each frequency for 32 times and sending the data back to Python. After each sweep, Python sends a new sweep command to keep updating the frequency response plot.)
Now here comes my question.. thanks for reading this far, haha.
As my main concern is the frequency resolution of <1Hz at higher time resolution (right now it is about 0,5s per sweep), I was wondering if it would be an interesting idea to use either a faster 12bit external ADC or maybe even a 13bit one to improve my time resolution. My thinking is as follows: A faster ADC might allow me to measure more averages in the same time frame possibly allowing for faster measurement sweeps. A 13bit ADC might also offer improved voltage resolution and perhaps make fitting more precise/constant so that a lower amount of averages can be used = faster measurements.
So, it boils down to the question of whether the Teensy 4.0 built-in ADC (I believe it is part of the main chip?) can be outperformed in terms of speed and resolution? And whether you think it would be possible for a 'beginner' like me.
If you have any other smart ideas, I would really appreciate new input as well
I thank you all very much in advance for the effort and hopefully we can come to some fruitful discussion.
Cheers,
Rens
EDIT1: Of course, if you think that there could be a lot to gain in terms of programming please feel free to request more of my code!
EDIT2: .. I should have thought about this post more carefully.. another plus I see in using an external ADC is that my board uses 5V for most of its components. With the Teensy ADC I am limited to 3.3V max, so I could also gain some resolution by using a 5V ADC (I can turn my buffer amplifier into a non-inverting amplifier and put some gain on the output of my logarithmic amplifier).
First let me say that I am in no shape or form a professional electrical engineer (I am a chemist-turned-electronics-hobbyist).
I am working on a pcb project where I try to make my own scalar network analyzer to measure quartz crystal resonances.
It looks similar to the design of Brett Killion (https://hackaday.com/2016/03/06/arduino-rf-network-analyzer/)
In short I am using an AD9851 DDS chip to generate my sine waves which are then passed through a LPF(70MHz cut-off) onto a buffer amplifier. This is then sent through a quartz crystal and the signal coming out at the other end is analyzed by a logarithmic amplifier. This outputs a certain voltage based on the envelope of the sine at its input. The output is again buffered and read by an analog pin of the microcontroller. The microcontroller that I use is the Teensy 4.0 and it is communicating over USB with a Python DAQ script using PySerial. Thus far I have been able to get quite nice results. However, I am now looking into speeding up the measurements to get a high time resolution.
I have posted on this forum before about the slow speed of data transfer likely caused by using the PySerial library. Simply put, I was using a too high frequency resolution (1Hz) for my measurements (requiring tons of data points per frequency sweep). I have since changed tactics and spend more of the computing power on the Teensy side. I use less data points per sweep (~10Hz resolution) and I fit a spline function to this result with much higher resolution on the Python side. To be able to get a good enough fit (1Hz resolution) I must average the 12 bit ADC measurement values at least ~30 times per frequency and do this for roughly 500 frequencies. I have confirmed that I am now mostly waiting on the Teensy by checking the available bytes in the PySerial buffer (it is mostly 0 and sometimes 2 when the Teensy sends the measurement data of a point).
(Part of the Teensy code is attached below, basic function is receiving a string from the Python script about the frequency sweep, converting this to a frequency range the Teensy can work with and using a serial Set_Frequency() function described by Analog Devices in their datasheet, measuring analogRead() at each frequency for 32 times and sending the data back to Python. After each sweep, Python sends a new sweep command to keep updating the frequency response plot.)
Now here comes my question.. thanks for reading this far, haha.
As my main concern is the frequency resolution of <1Hz at higher time resolution (right now it is about 0,5s per sweep), I was wondering if it would be an interesting idea to use either a faster 12bit external ADC or maybe even a 13bit one to improve my time resolution. My thinking is as follows: A faster ADC might allow me to measure more averages in the same time frame possibly allowing for faster measurement sweeps. A 13bit ADC might also offer improved voltage resolution and perhaps make fitting more precise/constant so that a lower amount of averages can be used = faster measurements.
So, it boils down to the question of whether the Teensy 4.0 built-in ADC (I believe it is part of the main chip?) can be outperformed in terms of speed and resolution? And whether you think it would be possible for a 'beginner' like me.
If you have any other smart ideas, I would really appreciate new input as well
I thank you all very much in advance for the effort and hopefully we can come to some fruitful discussion.
Cheers,
Rens
EDIT1: Of course, if you think that there could be a lot to gain in terms of programming please feel free to request more of my code!
EDIT2: .. I should have thought about this post more carefully.. another plus I see in using an external ADC is that my board uses 5V for most of its components. With the Teensy ADC I am limited to 3.3V max, so I could also gain some resolution by using a 5V ADC (I can turn my buffer amplifier into a non-inverting amplifier and put some gain on the output of my logarithmic amplifier).
Code:
void loop()
{
if (Serial.available()>0)
{
// reads the message sent, delimited by ;.
String message_str = Serial.readStringUntil('\n');
// buffer array for storing the message in char form temporarily
char buffer_array[64];
//Serial.println(message_str); // debugging line
// the String format is converted to C-string and stored in the buffer array
message_str.toCharArray(buffer_array, sizeof(buffer_array));
// strtok destroys data so a copy is made before with strcpy
strcpy(tempChars, buffer_array);
// this is used by strtok() as an index
char * strtokIndx;
// gets first part of C-string until delimiter and saves to variable
strtokIndx = strtok(tempChars,";");
freq_start = atol(strtokIndx);
// continues where last call left off and saves to variable
strtokIndx = strtok(NULL,";");
freq_stop = atol(strtokIndx);
// ditto ^
strtokIndx = strtok(NULL,";");
freq_step = atoi(strtokIndx);
new_command = 1;
}
if (new_command == 1)
{
digitalWrite(13,LOW);
Serial.write("b,");
for (int i=freq_start; i<=freq_stop; i+= freq_step)
{
Set_Frequency(i);
delayMicroseconds(10);
int AVG_MAG = 0;
uint16_t reading = 0;
if (AVERAGING == true) {
for (int i = 0; i < AVERAGE_SAMPLE; i++) {
AVG_MAG += analogRead(AD8310_MAG);
}
reading = AVG_MAG/AVERAGE_SAMPLE;.
}
uint8_t byte_array[2] = {reading >> 8, reading & 0xFF};
Serial.write(byte_array, 2);
}
Serial.write("s");
digitalWrite(13,HIGH);
new_command = 0;
}
}
Last edited: