Jump to content

passing matrices to external dll


Recommended Posts

Hi there, newbie here.

I did a search but could not find good answer to my question.

I have a simple LabView vi that takes in a 2D Array (user defines it, it is a "control" input) called A, an array b, and an initialized (all zeros) array x that is the same size as b.

Then I am trying to pass this to a C function in a library I'm writing, which will solve Ax=b.

I do not know in advance the size of the matrix A, but it is assumed to be square (therefore it is the same size as arrays b and x).

My problem is passing this matrix A into my function. I can pass b and x successfully, but my execution chokes up on A.

Here's my C function prototype:

_declspec(dllexport) unsigned char GaussJordan(double **A, double b[], double x[], unsigned long dim);

However, when I do to "configure" in the dll vi, it keeps generating the prototype:

unsigned char GaussJordan(double *A, double *b, double *x, unsigned long dim);

even when I tell it that A should be a 2D array.

When I stop my debugger right inside my C function call, I see that A[0] is 0, and then A[0][0] "cannot be evaluated".

When I change my function prototype to:

_declspec(dllexport) unsigned char GaussJordan(double A[3][3], double b[], double x[], unsigned long dim);

for instance, then with my debugger I can see inside my GaussJordan an A matrix that makes sense (i.e. is exactly what I passed in). However, this is then a problem because inside GaussJordan I have a function call to:

solveeqn(double **A, double b[], double[x], unsigned long size)

Which dies because A[3][3] is not of type double *[3].

Since I am using solveeqn on matrices of variable size elsewhere on the code, I cannot lock it to the size that labview desires. Not to mention that having to write a different vi to C interface on the day I decide to solve 4x4 matrices instead of 3x3 matrices is too much work.

So, the question is: how do I pass a variable-sized (assumed square) 2D array from LabView into a C function, if the size of this array is unknown in advance/unknown at compile time??

Any help will be greatly appreciated!

Thanks,

-Elisa.

Link to comment

QUOTE(blueshrimp @ Aug 21 2007, 11:26 AM)

Hi there, newbie here.

I did a search but could not find good answer to my question.

I have a simple LabView vi that takes in a 2D Array (user defines it, it is a "control" input) called A, an array b, and an initialized (all zeros) array x that is the same size as b.

Then I am trying to pass this to a C function in a library I'm writing, which will solve Ax=b.

I do not know in advance the size of the matrix A, but it is assumed to be square (therefore it is the same size as arrays b and x).

My problem is passing this matrix A into my function. I can pass b and x successfully, but my execution chokes up on A.

Here's my C function prototype:

_declspec(dllexport) unsigned char GaussJordan(double **A, double b[], double x[], unsigned long dim);

However, when I do to "configure" in the dll vi, it keeps generating the prototype:

unsigned char GaussJordan(double *A, double *b, double *x, unsigned long dim);

even when I tell it that A should be a 2D array.

When I stop my debugger right inside my C function call, I see that A[0] is 0, and then A[0][0] "cannot be evaluated".

When I change my function prototype to:

_declspec(dllexport) unsigned char GaussJordan(double A[3][3], double b[], double x[], unsigned long dim);

for instance, then with my debugger I can see inside my GaussJordan an A matrix that makes sense (i.e. is exactly what I passed in). However, this is then a problem because inside GaussJordan I have a function call to:

solveeqn(double **A, double b[], double[x], unsigned long size)

Which dies because A[3][3] is not of type double *[3].

Since I am using solveeqn on matrices of variable size elsewhere on the code, I cannot lock it to the size that labview desires. Not to mention that having to write a different vi to C interface on the day I decide to solve 4x4 matrices instead of 3x3 matrices is too much work.

So, the question is: how do I pass a variable-sized (assumed square) 2D array from LabView into a C function, if the size of this array is unknown in advance/unknown at compile time??

Any help will be greatly appreciated!

Thanks,

-Elisa.

I don't know why your 2D array isn't working, but.....

why don't you try passing it as a 1D array (re-shape the array to a 1D array). Since your array is square, you can re-shape the array within the DLL quite quickly back to a 2D array. You also can have a check to see if the size of the array really is a square number (1,4,9,16,25,36 and so on).

I might be wrong, but I think the re-allocation of an array from 2D to 1D where the overall number of elements remains constant is a trivial operation in LV, requiring no re-assignment of the data, just the Type descriptor. Again, amybe I'm way off here, but that's my take.

Shane.

Link to comment

LabVIEW can use multiple different ways to pass arrays between LabVIEW and external code. The options are Array Data Pointer, Array Handle and Array Handle Pointer.

  • Array Data Pointer passes a one-dimensional pointer to the array data. EDIT: This I think means 'datatype*' which is the same as 'datatype[]' hence the name one-dim pointer
  • Array Handle passes a pointer to a pointer that points to a four-byte (I32) value for each dimension, followed by the data.
  • Array Handle Pointer passes a pointer to an array handle.

If your C function expects other data types, you need to create a wrapper for the function in C to make the call. For detailed information see the pdf below.

http://www.ni.com/pdf/manuals/370109b.pdf

Link to comment

QUOTE(Neville D @ Aug 21 2007, 05:04 PM)

I know this doesn't directly address your question, but if you have the LV 8.5 Pro version, there are a lot of built-in VI's to solve Ax=B already. Why re-invent the wheel (and muck around with C in the process)?

Neville.

Because I am writing code for an embedded system (you need to tailor-write most embedded systems code so that it uses resouces most efficiently, as embedded systems are typically quite resource-constrained). For historical (and not very good) reasons, my company used LabView to prototype their algorithms. This makes them run very slow on a PC. Now we need to port to an embedded system. Ergo: need to write functions from scratch in C. The current C dll is used to validate our algorithm porting. It runs on a PC in parallel to the labview so that we can confirm that our C code does exactly what the labview does. Once we finish with the validation, we will get rid of the labview and run C native all the time.

Labview is nice for controlling motors and suchlike in the lab or university, but is not what you want to be running in a complex embedded system that ships out to customers. Too big and slow.

Anyway, thanks for your replies guys. Looks like I have to "flatten" the array or do lots of formatting tricks and deal with LV handles since C is tricky with matrix handling. Too bad, I was hoping there was a simpler way, oh well. :)

Link to comment

QUOTE(blueshrimp @ Aug 22 2007, 04:04 AM)

...Labview is nice for controlling motors and suchlike in the lab or university, but is not what you want to be running in a complex embedded system that ships out to customers. Too big and slow...

I think this comment is going to generate a few responses...

I have seen quite a few systems that ship to customer with embedded LabVIEW code. If the code is slow this is most likely due poor quality of the code. Nowdays with device such as CompactRio CompactFieldpoint this pretty "easy" to ship product with embedded LabVIEW code.

Just my 2c.

PJM

Link to comment

QUOTE(RiverdaleVIEW @ Aug 21 2007, 07:58 AM)

My C may be a litle rusty, but is "**A" the proper way to declare a 2D array? Won't that just declare a pointer to a pointer?

I'd try using an array format in the prototype, and pass in a 2d array initialized to the proper size in LabVIEW through the pointer in the Library call.

Well a 2D array in C is VERY ambigious. Without knowing more exactly what the programmer did intend and use you can generally not say for sure how it is implemented just from the prototype.

You can implement a 2D array as one single chunk of memory with allo rows (or for the kick colomns) put after each other). This is the way LabVIEW handles 2D arrays. It is as far as the memory layout is concerned just a single 1 dimensional array with all rows streamed (serialized). This is pretty efficient and cool with one single drawback. Since you only know the number of rows and columns for such an array each row will have to have the same length, resulting really into an array of rows * columns elements.

Another possibility is to create an array of pointers to 1D arrays. This results in the int **a syntax and is a bigger load for the memory manager. This array can NOT be created nor passed by LabVIEW directly to a DLL nor exported from a LabVIEW DLL. One of the reasons is that there is no way for LabVIEW (and any C compiler actually) to know if this is just a double referenced pointer to a single variable or if it is an array of pointers. int *a[] would be a bit clearer in that sense but traditionally C compilers make no difference between int *a[] and int **a.

So if you have an int *a[] or int **a parameter anywhere in your DLL functions, you are going to have to create a C wrapper function in this or a saparate DLL to translate between LabVIEW and your DLL.

Rolf Kalbermatter

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.