views:

103

answers:

4

It seems like I'm on here asking a question just about every day now. I'm not sure if that's a good thing or a bad thing...

Today's "Flavor-Of-The-WTF" involves my complete and utter cluelessness when using a function from a NI Measurement Studio object. As with most of my previous questions, this is in regards to an internship project where I've been tasked with translating a VB6 project into C# in the .Net Framework 2.0.

The original VB code looks something like this:

Public Sub FFT(ZData() As Single, FFTData() As Single)
    Dim realdata As Variant
    Dim imgdata As Variant

    // (... Some unrelated other code in here ...)

    // Here we pass three variables to a NI CWDSP object's ReFFT function
    CWDSP1.ReFFT ZData, realdata, imgdata

    // (... More unrelated code ...)
End Sub

I stuck in a MsgBox at one point to see how realdata and imgdata were being interpreted. They're both Double()s. It works just fine for what it does, in the original program. Admittedly, my intimate knowledge of the original program is only mediocre, as I picked up the project recently, and only have a few years of programming under my belt (and no years of mechanical engineering. The programmer was a mechanical engineer, the application itself a measuring tool for machine output).

Taking the code over to C#, I tried rewriting it as such:

private void FFT(float[] ZData, float[] FFTData){
    double[] realData = new double[1000];
    double[] imgData = new double[1000];

    // (... Unrelated intermediate code ...)

    DSP.ReFFT(ZData, realData, imgData);

    // (... Unrelated intermediate code ...)
}

As you can see, I started by doing it basically the same way as the original VB. The following error came up: Cannot Convert double[] to ref object

Well, that's no good. So I tried: DSP.ReFFT(ZData, ref realData, ref imgData);

Only to get back: Cannot Convert ref double[] to ref object

So I did what I thought was obvious. I boxed realData and imgData into objects, and passed them to the function. It's not too fond of that, however. If I pass the new objects without ref, it insists that I need to pass them with ref. If I pass them with ref, it gives me the error:

Cannot Convert ref double[] to ref object.

Huh... that looks familiar. I finally get the compiler to stop producing errors when I change double[] to Object in the instantiation of the two variables. But... when I run the function, I get a Type Mismatch error.

I've really got no idea where I go from here. There's little to no information about programming for C# with Measurement Studio out there on the internet. Even if there was, I'm sure the solution is much more simple than I expect it to be. History has taught me that when there's a bug I can't figure out, it's almost always something stupid.

+2  A: 

Give this a go in your FFT function:

object realData = new double[1000];
object imgData = new double[1000];
ReFFT(new object(), ref realData, ref imgData);

double[] realDataArray = (double[])realData;

by instantiating the object as a new double[1000], you are establishing that although you are treating realData as an object, its' underlying type is double[]. Later, after the method call, you're closing the realData array by creating a new one and casting the previous one to the original type. It may be more boxing/unboxing than is strictly needed, but hopefully it gets the point across

Try 2:

double[] somerealData = new double[1000];
double[] someimgData = new double[1000];
object realData, imgData;
realData = somerealData;
imgData = someimgData;

ReFFT(new object(), ref realData, ref imgData);

double[] realDataArray = (double[])realData;
Console.WriteLine(realDataArray.Length);
realDataArray[0] = 1.0d;
Console.WriteLine(realDataArray[0]);

I've tried the second approach in a .NET 2.0 console app, so I'm pretty sure that it works. If it doesn't, then we'll need to take a step back and re-assess the situation.

Try 3: Just noticed that the first parameter of the ReFFT method is a float[]. Let's try this:

double[] somerealData = new double[1000];
double[] someimgData = new double[1000];
//float[] zData placeholder since array comes from input param

object realData, imgData, zObj;
realData = somerealData;
imgData = someimgData;
zObj = zData;

ReFFT(zObj, ref realData, ref imgData);

double[] realDataArray = (double[])realData;
Console.WriteLine(realDataArray.Length);
realDataArray[0] = 1.0d;
Console.WriteLine(realDataArray[0]);
Josh E
I like the idea, but it's one I already tried (and tried again just now, to be extra sure). I still get the Type Mismatch error that's plaguing me. I noticed that when I put a breakpoint in the program, it tells me that "realData" and "imgData" have types of `object{double[]}` as opposed to pure `object`. Maybe that has something to do with it.
KChaloux
Hmmm. I tried out the code in my answer in LINQPad and it worked fine. Updating answer with a different approach
Josh E
Note that the FFT function comes from an external source: National Instruments Measurement Studio. The company uses it for almost everything, and it's given me a lot of trouble, working in subtly different ways from VB to C# with almost no documentation. I don't know if that might be causing my problem...
KChaloux
@KChaloux: it says the object's type is `object{double[]}` because all .NET types, including `double[]`, inherit from `object`. `object{double[]}` means that the variable's declared type is `object`, and its actual type is `double[]`
Thomas Levesque
well, in *theory*, it shouldn't have an effect on the code since it's simply modifying the arrays passed in via ref. I've tried messing with the arrays in the ReFFT func in my sample app, and it doesn't affect the outcome - it still works
Josh E
I've still got the same error as of Try 2. I went so far as to even commenting out ALL unrelated code in the function and copy/pasting your exact example in, to make sure it wasn't some unseen mistake on my part. My exact error: `{"Type mismatch. (Exception from HRESULT: 0x80020005 (DISP_E_TYPEMISMATCH))"}`Something I noticed when I stuck a breakpoint on there, though: The method is called in a Timer. The very first time it goes through, it doesn't seem to give me an error. I'm going to check something...
KChaloux
Well... there is a serious problem here. I just tried to pass: `object test = new object();` `DSP.ReFFT(test, ref test, ref test);`It returned another `Type Mismatch` error. I understand that there was no actual data in that object, but I have NO idea where the type mismatch could be coming from. The error says it's on the same line as the function call, but I can't help but wonder if there's something deeply wrong inside the function itself...
KChaloux
Do you know what the *test* object is used for in the function, i.e. what type does the function use it as?
Josh E
I wish I did, but I haven't been able to find out the actual meat of the function, beyond its basic signature. I don't imagine National Instruments would go around handing out their source code.
KChaloux
Just noticed that the first parameter is supposed to be an array of float... try using the same technique with that parameter that we have been previously trying and let's see what happens
Josh E
Unfortunately I already considered that and tried it. I think I'm about to give National Instruments a call and see if they can't figure this out...
KChaloux
I think that's an excellent idea
Josh E
A: 

What about just trying to send it an object, then check the type of what you get back. So something like this:

    private void FFT(float[] ZData, float[] FFTData)
    {
        object realData = new object();
        object imgData = new object();

        // (... Unrelated intermediate code ...)

        DSP.ReFFT(ZData, ref realData, ref imgData);

        // Find out what the type actual is (this will probably only work
        // if the values are assigned with the new data type)
        // but worth a shot:
        type t1 = typeof(realData);
        type t2 = typeof(imgData);

        // if t1 and t2 show the actual types, replace the
        // type above (new object() with the type here)

        // (... Unrelated intermediate code ...)
    }

Update: Just saw your last comment above. You'll probably want to create three seperate objects. Test1, Test2 and Test3 all as new object()'s.

From this post, it says for documentation to do the following:

Start >> All Programs >> National Instruments >> Measurement Studio 7.1 for VS .NET 2003 >> Measurement Studio Documentation

Then select "Measurement Studio" under the Filter pull down.

Now navigate the help tree to "NI Measurment Studio Help >> NI Measurement Studio .NET Class Library >> Reference >> National Instruments.Analysis.SpectralMeasurements >> Measurements Class >> Methods >> ReFFT??? Method.

SwDevMan81
That's the bizarre thing that leads me to believe there's something terribly wrong with the function itself. Even if I send it all objects, it reports a Type Mismatch error.
KChaloux
No such luck in regards to creating 3 separate objects. Unfortunately I don't really know what it's doing with them, so if the error is on the inside of the function, it could be anything.
KChaloux
Hmm, yeah, have you tried using the 'out' keyword instead of 'ref', for the double[]'s?
SwDevMan81
I actually hadn't, but apparently it results in a compile time error and tells me that I *must* use the `ref` keyword.
KChaloux
Wow, that is weird. I updated my post and put a link to some supposed documentation... maybe you can see if there is a function definition for it.
SwDevMan81
A: 

You say that DSP is COM, and the odd errors you're getting suggests to me that the underlying problem is "marshalling" the parameters between .NET and COM. I am no expert on this, so this is more along the lines of a suggestion to investigate how one would encapsulate DSP in a COM-interop layer and calling it through that layer.

Here's a good starting point on MSDN: Introduction to COM Interop

Cyberherbalist
A: 

I never did figure out what was wrong with the function, so this answer might not help some people. Nevertheless, if you're using Measurement Studio in C# like I am and need to do a FFT, there was apparently a .NET class that includes it, and appears to work.

NationalInstruments.Analysis.Dsp.Transforms.FFT (and InverseFFT and a bunch of others). I'd still love to know what the deal with the other one was, though...

Thanks everyone for your suggestions. They were all logical ones that probably should have worked, but didn't for some unknown reason (likely relating to the inner workings of the function).

KChaloux