How to specify output type in MATLAB when using calllib - matlab

Can I specify the output type when using calllib? My problem is MATLAB is automatically converting my output to a double even though I need an int64 and am losing needed precision.
Example
I have the following function defined in my_header.h
__int64 my_function(int arg1);
I can call the function like this:
loadlibrary('my_library', 'my_header.h')
output = calllib('my_library', 'my_function', arg1)
But then output is a double and I am losing needed precision.
What I tried
output = int64(calllib('my_library', 'my_function', arg1))
as well as
output = zeros(1, 'int64')
output(1) = calllib('my_library', 'my_function', arg1)
but these just convert my double to int64 after it has already lost the needed precision.

Related

Creating a PyMemoryView with a specific format

I am exposing a PyMemoryView in C on a set of data, like so:
PyMemoryView_FromMemory((char *)ibuf->rect, pixels * sizeof(uint), PyBUF_WRITE);
That data is floating-point data, however, so attempting to do this:
mv = get_my_memory_view()
mv[0] = 3.141
yields the following error:
TypeError: memoryview: invalid type for format 'B'
This is, of course, because the memoryview assumes the underlying data to be byte data, not float. How would I ensure that the memoryview returned from my module has a float specifier?
The easiest way would probably be to use the cast method of the memoryview to get a new memoryview with the correct format. There isn't a direct C-API method to do it, so just call it like any other Python method:
mview_double = PyObject_CallMethod(mview_bytes, "cast", "s", "d");
this assumes double data - if it's float data then you should change the "d".
In the original call to PyMemoryView_FromMemory I think pixels * sizeof(uint) is wrong since you've told us the data-type is a floating-point type. Maybe pixels*sizeof(ibuf->rect[0])?

convert number string into float with specific precision (without getting rounding errors)

I have a vector of cells (say, size of 50x1, called tokens) , each of which is a struct with properties x,f1,f2 which are strings representing numbers. for example, tokens{15} gives:
x: "-1.4343429"
f1: "15.7947111"
f2: "-5.8196158"
and I am trying to put those numbers into 3 vectors (each is also 50x1) whose type is float. So I create 3 vectors:
x = zeros(50,1,'single');
f1 = zeros(50,1,'single');
f2 = zeros(50,1,'single');
and that works fine (why wouldn't it?). But then when I try to populate those vectors: (L is a for loop index)
x(L)=tokens{L}.x;
.. also for the other 2
I get :
The following error occurred converting from string to single:
Conversion to single from string is not possible.
Which I can understand; implicit conversion doesn't work for single. It does work if x, f1 and f2 are of type 50x1 double.
The reason I am doing it with floats is because the data I get is from a C program which writes the some floats into a file to be read by matlab. If I try to convert the values into doubles in the C program I get rounding errors...
So, (after what I hope is a good question,) how might I be able to get the numbers in those strings, at the right precision? (all the strings have the same number of decimal places: 7).
The MCVE:
filedata = fopen('fname1.txt','rt');
%fname1.txt is created by a C program. I am quite sure that the problem isn't there.
scanned = textscan(filedata,'%s','Delimiter','\n');
raw = scanned{1};
stringValues = strings(50,1);
for K=1:length(raw)
stringValues(K)=raw{K};
end
clear K %purely for convenience
regex = 'x=(?<x>[\-\.0-9]*),f1=(?<f1>[\-\.0-9]*),f2=(?<f2>[\-\.0-9]*)';
tokens = regexp(stringValues,regex,'names');
x = zeros(50,1,'single');
f1 = zeros(50,1,'single');
f2 = zeros(50,1,'single');
for L=1:length(tokens)
x(L)=tokens{L}.x;
f1(L)=tokens{L}.f1;
f2(L)=tokens{L}.f2;
end
Use function str2double before assigning into yours arrays (and then cast it to single if you want). Strings (char arrays) must be explicitely converted to numbers before using them as numbers.

printing scalar as int32 in Matlab

I'm trying to print scalar as it would look like if it was int32. That is, if I have 2532063508, if I write it in 4 bytes and read as int32, I would read -1762903788.
using int32 function in Matlab didn't work, because the way it works is, values outside the range [-2^31,2^31-1] map to the nearest endpoint.
So I tried to use typecast:
typecast(uint32(2532063508), 'int32')
works perfectly, but if I write e.g. -1 there, uint32() returns 0 so it fails.
P.S. I want it to work for signed integers as input as well, that is, for -1 it should return -1
any suggestions?
You can do calculations in int64 then convert to uint32:
f = #(x)typecast(uint32(mod(int64(x),int64(2)^32)),'int32');
Or
function y = f(x)
y = typecast(uint32(mod(int64(x),int64(2)^32)),'int32');
end
So f([-1, 2532063508]) returns [-1, -1762903788].

OMShell returns String but doesn't recognize it

For one of my models, it is required to read the final value of all variables and set them as initial value for the next simulation. My real problem is due to types defined in OMShell. As can be seen in the scripting commands of OpenModelica, there are String type and "VariableName", "TypeName" types. To elaborate the difference:
// The following loads the Standard Modelica Library
>> loadModel(Modelica)
true
// The following throws an error
>> loadModel("Modelica")
The reason is that the loadModel function doesn't expect a string variable. It expects the name of the model. Returning my problem, I tried to use val function as in the following, so that I can give the value as the initial value of the next simulation.
>> final_time := 200;
>> myVarValue := val(myVar, final_time);
This can be done for each variable by using a for-loop, I thought as I have several variables and I realized the problem at this point.
// Get the list of all variables
>> myVarList := readSimulationResultVars(currentSimulationResult);
>> size(myVarList)
{724}
// The problem is that this list contains strings
>> myVarList[1]
"mySubSystem.myComponent.myPin.v"
// Following throws an error as it doesn't expect a string
>> val(myVarList[1], final_time)
How can I remove "" from the string that OMShell returns to me? I need to convert "myVar" to myVar so that I can use it as an input for the functions of OMShell.
You can use the stringVariableName function.
>>> vars:=OpenModelica.Scripting.readSimulationResultVars(currentSimulationResult)
{"r","time"}
>>> val(stringVariableName(vars[1]), 0.0)
1.0

MATLAB wchar_t Equivalent Type

The C-Code is stored in a DLL. I can load the DLL in MATLAB with the loadlibrary function. I am having trouble passing the wchar_t*[] parameter to the function. I do not know how to create this data type in MATLAB. Does anyone know how to create this type to pass to the calllib function?
MATLAB Code:
loadlibrary('test.dll', 'test.h');
str = '0';
ptr = libpoiner('voidPtrPtr', [int8(str) 0])
calllib('test.dll', 'testFunction', ptr) %this parameter does not match the wchar*[] type
outVal = ptr.Value
C-Code:
void testFunction(wchar_t* str[])
{
str[0] = L"test";
}
Output:
MATLAB allows the function to complete. The outVal variable is filled with garbage values.
If you are able to modify the C header files, you may try the following:
Adjust the header file to convert all wchar_t * to unsigned short *.
On the MATLAB side, the corresponding type would then be a uint16 array.
You could then typecast the uint16 array to char.
I figured it out. I changed the MATLAB code to the following:
loadlibrary('test.dll', 'test.h');
str = '0';
ptr = libpoiner('voidPtrPtr', [uint16(str) 0])
calllib('test.dll', 'testFunction', ptr) %this parameter does not match the wchar*[] type
outVal = ptr.Value
expectedOutput = char(outVal); %convert to ASCII
It outputs the values in decimal which confused me. When I converted them to ASCII, everything made sense.