0
Offline
Newbie
Karma: 0
Posts: 35
Arduino rocks
|
 |
« on: February 07, 2013, 10:23:06 am » |
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 usAssume 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/35639http://arduino.cc/forum/index.php/topic,6549.0.htmlhttps://sites.google.com/site/measuringstuff/the-arduino#TOC-Sample-Rates
|
|
|
|
« Last Edit: February 24, 2013, 04:55:22 am by SuperR »
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 101
Posts: 9551
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #1 on: February 07, 2013, 02:14:55 pm » |
\Can you give a glimpse of the complexity of the code you want to implement?
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 35
Arduino rocks
|
 |
« Reply #2 on: February 08, 2013, 02:10:51 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
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 101
Posts: 9551
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #3 on: February 08, 2013, 12:46:58 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.
|
|
|
|
|
Logged
|
|
|
|
|
United Kingdom
Offline
Faraday Member
Karma: 146
Posts: 4887
|
 |
« Reply #4 on: February 09, 2013, 06:00:46 am » |
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.
|
|
|
|
|
Logged
|
Formal verification of safety-critical software, software development, and electronic design and prototyping. http://www.eschertech.com
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 35
Arduino rocks
|
 |
« Reply #5 on: February 11, 2013, 11:27:07 am » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 9
Posts: 839
|
 |
« Reply #6 on: February 11, 2013, 12:40:18 pm » |
I don't understand how you plan to have output to an accelerometer.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 35
Arduino rocks
|
 |
« Reply #7 on: February 11, 2013, 12:58:13 pm » |
From an accelerometer, not to. The accelerometer is my sensor
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 35
Arduino rocks
|
 |
« Reply #8 on: February 12, 2013, 06:52:00 am » |
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 
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 35
Arduino rocks
|
 |
« Reply #9 on: February 24, 2013, 03:06:00 am » |
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.pdfTherefore, 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 Read 1 byte, (8 I/O pins) from ADC1 Read 1 byte, (8 different I/O pins), from ADC2 Put "Byte" high, Read second byte from ADC1 Read second byte from ADC2 That would cost me around 20 pins for 2ADC's, leaving me plenty pins for the DAC, which uses around 20 too.
|
|
|
|
« Last Edit: February 24, 2013, 05:21:21 am by SuperR »
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 35
Arduino rocks
|
 |
« Reply #10 on: February 28, 2013, 10:30:02 am » |
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! >> 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
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 35
Arduino rocks
|
 |
« Reply #11 on: February 28, 2013, 12:37:15 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 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
|
|
|
|
|
Logged
|
|
|
|
|
Netherlands
Offline
Tesla Member
Karma: 101
Posts: 9551
In theory there is no difference between theory and practice, however in practice there are many...
|
 |
« Reply #12 on: February 28, 2013, 02:25:30 pm » |
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?
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 35
Arduino rocks
|
 |
« Reply #13 on: March 01, 2013, 01:07:28 am » |
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.
|
|
|
|
« Last Edit: March 01, 2013, 03:04:43 am by SuperR »
|
Logged
|
|
|
|
|
|