Go Down

Topic: High speed read of bipolar signal, -> ADC (LTC1605) (Read 5734 times)previous topic - next topic

SuperR

Feb 07, 2013, 04:23 pmLast Edit: Feb 24, 2013, 10:55 am by SuperR Reason: 1
Hi,

I am starting experiments on a setup next week and was interested in using a standalone Arduino application next to the (overkill) Matlab dSpace interface. I really like Matlab and Simulink, but I am intrigued by the idea of implementing a control loop within the Atmega 328P.

Here's the setup;
Reference input, an audio signal, so both positive and negative voltages
Sensor output, an accelerometer, putting out both positive and negative voltages

Once I find a control loop, say, just an error times a transferfunction, it would be nice to implement it in an Arduino environment

Here's the issue;
I want a "sample 2 inputs -> substrackt -> run filter-> output"-time of say 1/10000 s = 100 us
Assume the filter to be quite "filled with dynamics". So no simple 1 zero 2 poles transfer function.

Do any of you have experience with similar implementations? I am not sure whether the Atmega can do this at ease or if it is impossible.

I read about implementing Simulink code on an Arduino. That would be awesome, but then again, I am not sure the (calculation)speed is high enough for my goals.

If it's impossible to do, so be it. However, if with little modifications something like this can be accomplished, that would be great!

http://www.mathworks.com/matlabcentral/fileexchange/35639
http://arduino.cc/forum/index.php/topic,6549.0.html

robtillaart

#1
Feb 07, 2013, 08:14 pm
\Can you give a glimpse of the complexity of the code you want to implement?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

SuperR

#2
Feb 08, 2013, 08:10 am
Something like this is the discretized transfer function;

>> c2d(C,0.0001)

Transfer function:

7.716 z^7 - 37.57 z^6 + 73.23 z^5 - 71.39 z^4 + 34.81 z^3 - 6.785 z^2 - 0.001332 z

- 1.96e-008

-------------------------------------------------------------------------------------

z^7 - 3.882 z^6 + 5.648 z^5 - 3.652 z^4 + 0.8852 z^3 - 1.632e-005 z^2 + 1.002e-010 z

- 2.053e-016

robtillaart

#3
Feb 08, 2013, 06:46 pm

such a formula can be calculated quite well with an Arduino.

float x1 = ((((((7.716 * z - 37.57) * z + 73.23) * z  - 71.39) * z + 34.81) * z - 6.785) * z - 0.001332) * z - 1.96e-008

This trick brings it down to 14 "simple" float operations instead of using power

Main problem might be that the Arduino only supports 32bit IEEE754 floats with ~7 significant digits.

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

dc42

#4
Feb 09, 2013, 12:00 pm
If you need to sample 2 inputs, you face an immediate problem which is that the Arduino in its default configuration takes about 100us to do a single ADC conversion. If you can tolerate reducing the number of bits resolution below 10, then you can increase the ADC clock frequency and achieve faster conversion times.

You will need to write the code something like this so that you are not waiting on the ADC conversions:

Start conversion of input A
Do half of the maths on the previous pair of samples
Wait for conversion to complete
Read the result of the conversion of input A
Start conversion of input B
Do the remaining half of the maths on the previous pair of samples
Wait for conversion to complete
Read the result of the conversion of input B
Repeat from start

What I don't know is whether you can do the maths fast enough on an Arduino, but you can measure that yourself.

You will be sampling the inputs at slight different times (maybe 50us apart). If that isn't acceptable, you will have to use an external ADC chip with faster conversion time.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

SuperR

#5
Feb 11, 2013, 05:27 pm
I think 10bit resolution is fine. However, I have both positive and negative voltages. If it helps to use an external ADC and DAC, I think that's possible. And DC42, nice to know that code can be run while I wait for the ADC is running. I'll investigate further within the next couple weeks.

michinyon

#6
Feb 11, 2013, 06:40 pm
I don't understand how you plan to have output to an accelerometer.

SuperR

#7
Feb 11, 2013, 06:58 pm
From an accelerometer, not to. The accelerometer is my sensor

SuperR

#8
Feb 12, 2013, 12:52 pm
I have been informed of the Arduino Due, which might solve my speed-problems. An order is pending so I should be up and running shortly. More to come

SuperR

#9
Feb 24, 2013, 09:06 amLast Edit: Feb 24, 2013, 11:21 am by SuperR Reason: 1
Ok, there's an update on the situation;

Instead of using the analogread or shaping the analog signals so that they fit the requirements of the Arduino Due internal adc, I am going to implement a dedicated ADC. The one available at the lab is a LTC1605. Just the IC, I need to built a PCB so I am free to implement different/extra IC's.

http://cds.linear.com/docs/en/datasheet/1605fc.pdf

Therefore, the questions now turns into;
What is the fastest/best way to turn those 16 output pins of the IC into a value in my Arduino Due? And even worse, I would read two of these ADC's.

After studying the spec sheet my steps would be;
Put CS low, (initiate conversion of ADC)
Wait 8 uS, time it takes between CS low and valid data
Put "Byte" high,

That would cost me around 20 pins for 2ADC's, leaving me plenty pins for the DAC, which uses around 20 too.

SuperR

#10
Feb 28, 2013, 04:30 pm
ADC is up and running, at least, we receive data which matches the voltage on the multimeter . I was planning on using a TXB0104 for the 5V to 3.3V conversion. That way, I can safely measure the 2 8bit streams. Since I have to wait for parts and we would like to keep our code-progress up, for today, a simple voltage divider will be attemped, 2 r's op 2k5 I thought were used. I'll keep you updated.

If someone has an idea on how to implement the discretized transferfunction, please inform me!

Code: [Select]
`>> c2d(C,0.0001) Transfer function:                                                                                     7.716 z^7 - 37.57 z^6 + 73.23 z^5 - 71.39 z^4 + 34.81 z^3 - 6.785 z^2 - 0.001332 z                                                                                                                                                           - 1.96e-008                                                                                      -------------------------------------------------------------------------------------                                                                                     z^7 - 3.882 z^6 + 5.648 z^5 - 3.652 z^4 + 0.8852 z^3 - 1.632e-005 z^2 + 1.002e-010 z                                                                                                                                                         - 2.053e-016 `

SuperR

#11
Feb 28, 2013, 06:37 pm
Hmmz, the ADC is taking around 30us. I was hoping it would be faster. I hope I can read the ports faster. I was hoping to simultaneously read all 8 bits instead of ready each one individually. Please comment

Code: [Select]
`inline void digitalWriteDirect(int pin, boolean val){  if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;  else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;}inline int digitalReadDirect(int pin){  return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);}byte RC = 40;byte BYTE = 42;byte b1_pin = 22, b2_pin = 24, b3_pin = 26, b4_pin = 28, b5_pin = 30, b6_pin = 32, b7_pin = 34, b8_pin = 36;int b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16;int output;float outputV;//long bit1, bit2, bit3, bit4, bit5, bit6, bit7, bit8;void setup() {pinMode(b1_pin, INPUT);pinMode(b2_pin, INPUT);pinMode(b3_pin, INPUT);pinMode(b4_pin, INPUT);pinMode(b5_pin, INPUT);pinMode(b6_pin, INPUT);pinMode(b7_pin, INPUT);pinMode(b8_pin, INPUT);pinMode(RC, OUTPUT);pinMode(BYTE, OUTPUT);digitalWriteDirect(RC,HIGH);digitalWriteDirect(BYTE,LOW);// Serial.begin(9600);}void loop() {  digitalWriteDirect(BYTE,LOW);  digitalWriteDirect(RC,LOW);    delayMicroseconds(1);   digitalWriteDirect(RC,HIGH);   delayMicroseconds(6);     b9 = digitalReadDirect(b1_pin);  b10 = digitalReadDirect(b2_pin);  b11 = digitalReadDirect(b3_pin);  b12 = digitalReadDirect(b4_pin);  b13 = digitalReadDirect(b5_pin);  b14 = digitalReadDirect(b6_pin);  b15 = digitalReadDirect(b7_pin);  b16 = digitalReadDirect(b8_pin);  //bit_val = b8 + 10*b7 + 100*b6 + 1000*b5 + 10000*b4 + 100000*b3 + 1000000*b2 + 10000000*b1;    digitalWriteDirect(BYTE,HIGH);  delayMicroseconds(1);  b1 = digitalReadDirect(b1_pin);  b2 = digitalReadDirect(b2_pin);  b3 = digitalReadDirect(b3_pin);  b4 = digitalReadDirect(b4_pin);  b5 = digitalReadDirect(b5_pin);  b6 = digitalReadDirect(b6_pin);  b7 = digitalReadDirect(b7_pin);  b8 = digitalReadDirect(b8_pin);    output = (b2 << 14) + (b3 << 13) + (b4 << 12) + (b5 << 11) + (b6 << 10) + (b7 << 9) + (b8 << 8) + (b9 << 7) + (b10 << 6) + (b11 << 5) + (b12 << 4) + (b13 << 3) + (b14 << 2) + (b15 << 1) + b16;   if (b1 == 1) { outputV = (-32767 + output)/3276.8; } // 10V per 2^15 bit  else {outputV = output/3276.8; } // 10V per 2^15 bit`

robtillaart

#12
Feb 28, 2013, 08:25 pm
Quote
If someone has an idea on how to implement the discretized transferfunction, please inform me!

Whjat do you mean exactly, I posted a faster version of your function in reply 3 .
Have you measured the time difference?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

SuperR

#13
Mar 01, 2013, 07:07 amLast Edit: Mar 01, 2013, 09:04 am by SuperR Reason: 1
Well, either I interpreted your code wrongly, or you did mine.
The z in the transferfunction is not some value but the "Z transform".

Imagine the following problem;

I need to store data from the past in some container/array;
Some "error", which stores values of the past 7 values of error
Some "u", which stores values of the past 7 values of u.

Define k to be the current sample. u(k) therefore will be the output of my equation.
Define (k-7) to be the data from a variable 7 samples ago. error(k-7) should be the value of error, 7 samples ago.

Now here comes the "fun";
To calculate u(k), I need to read all values, from error(k-7) to error(k) and u(k-7) to u(k-1). I then need to multiply those values by a certain set of 13 fixed values, say 7.7662, 2.34632 etc.
After that, I need to sum those values to get to u(k), which is send to the DAC.

Before the next calculation loop begins, I need to shift every "past value" one instance further away to the past. I only need to store the last x values so when the sample is too old, I can discard it.

I think the use of an array should be ideal. Is there a (dis)advantage of using 2 arrays for each value over storing the values in 1 "big" (14 value) array?

And inevitably, there's the float/integer issue again. Since I don't want to waste previous run-time, I was thinking of scaling up all values by 10, 100 of 1000 so that I can use 2byte integers for my calculations instead of the 4 byte floats. Will that help with the speed or is the difference negligible? I would think the calculation time would double, but I'm not the expert.

Go Up