Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QByteArray to Float Array



  • Hi,

    I am fairly new to QT and C++; I have very good experience in C and HDL and its been a long time since I touched object orientated programming languages but I am slowly getting back into it.

    Anyway I have a QT GUI working along with QCustomPlot , doing some networking and some file streaming. I can successfully capture the TCP packets from the network (8k packets) into a QByteArray and stream it into a file in binary and then read successfully in MATLAB with no packet loss or problems.

    However I am now trying to get it to plot on screen in real-time using QCustomPlot,I have tested everything else and it is all ok, the only issue is that I can figure out how to convert a QByteArray which contains 2048 float samples into a single floating point number which can be sent for plotting on the QCPColourMap (in addition to this it accepts arguments of double). I am looking for the most efficient way to convert each sample in the ByteArray to floating point so that it can be plotted, custom functions will not be appropriate as the conversion at max capacity may be called at 245,000 times per second.

    I have looked at various posts but I am not sure how I can adapt them as they assume that the entire QByteArray contains 1 floating samples (4 bytes) whereas my QByteArray over network contains 8192 Bytes. I have leant away of bit banging and forceful manipulation solutions, which look to be quite inefficient. I am certain that I am not the first person to have to do this also, if anyone has a better route regarding the QByteArray I am all ears.

    Thanks in advance.



  • @Renegade243
    Your code is always reading the first 4 bytes
    And

    const double* ptrDouble = reinterpret_cast<const double*>(ptrFloat);
    

    is definitely wrong in this case. Should change that to

        while(tcpClient.bytesAvailable()){
            data_in = tcpClient.read(PayloadSize); // 2048 samples
            int numSamples = data_in.size() / 4;
            const float* ptrFloat = reinterpret_cast<const float*>(data_in.constData());
            for (int i=0; i<numSamples; ++i){
                cout << i << " Float Val: " << *ptrFloat << endl;
                double readDouble = *ptrFloat ;
                cout << i << " Double Val: " << readDouble << endl;
                colorMapRTI_1->data()->cellToCoord(i, 0, &x, &y);
                colorMapRTI_1->data()->setCell(i, 0, readDouble);
                ptrFloat++;
            }
            ui->rti_1->replot();
            colorMapRTI_1->rescaleDataRange();
        } // end of while
    


  • @Renegade243 said in QByteArray to Float Array:

    they assume that the entire QByteArray contains 1 floating samples (4 bytes) whereas my QByteArray over network contains 8192 Bytes

    Not sure what you mean. QByteArray QByteArray::mid(int pos, int len = -1) gives you access to bytes in the middle of the array, const char *QByteArray::constData() const gives you access to the raw data bytes, or you can just index into the array? Maybe I'm misunderstanding your question....


  • Lifetime Qt Champion

    Hi and welcome to the forums.
    So in your bytearray of 8192
    how many values and how many bytes pr value ?



  • @JonB

    Ok this might be some useful syntax, but how could I convert every 4 bytes into a float efficiently, I am surprised there is not a built in function which can do this ?

    @mrjj

    Thanks, I have 2048 float samples, 4 bytes per float in an 8K (8192 bytes) QByteArray received from TCP socket, like below:

    QByteArray data_in;
    data_in = tcpClient.read(PayloadSize); // 2048 samples
    

    and I need to get the samples out one by one to pass to the plotting function (argument accepts double but I can sort this after):

            for (int i=0; i<2048; ++i){
                colorMapRTI_1->data()->cellToCoord(i, 0, &x, &y);
                colorMapRTI_1->data()->setCell(i, 0, "double data sample");
            }
    

    Thanks for your time.



  • Would this work? I'm using the Audio Input Example for reference.

    const char *ptr = data_in.constData();
    int numSamples = data_in.size() / 4;
    for (int i = 0; i < numSamples; ++i) {
        const float* ptrFloat = reinterpret_cast<const float*>(ptr);
        //use the float by: *ptrFloat
        ptr += 4;
    }
    

  • Lifetime Qt Champion

    @Bonnie no need to cast every time:

    const float* ptrFloat = reinterpret_cast<const float*>(data_in.constData());
    int numSamples = data_in.size() / 4;
    for (int i = 0; i < numSamples; ++i) {
        //use the float by: *ptrFloat
        ptrFloat++;
    }
    


  • Hi thanks for the replies all,

    I've given the code from @Bonnie and @Christian-Ehrlicher a go, but they seem to be spitting out constant values for the float "0.14425" or something like that, I am very confident my C program is not sending that as the data packet, since the Hex values in the packet sniffer do not show any obvious pattern. The full payloads are definitely getting there to the program and it is reporting a full 2048 sample packet. I will also need to convert the QCPColorMap to accept only float data at some point. The code that I am using is below:

        while(tcpClient.bytesAvailable()){
            data_in = tcpClient.read(PayloadSize); // 2048 samples
            int numSamples = data_in.size() / 4;
    
            for (int i=0; i<numSamples; ++i){
                const float* ptrFloat = reinterpret_cast<const float*>(data_in.constData());
                cout << i << " Float Val: " << *ptrFloat << endl;
                const double* ptrDouble = reinterpret_cast<const double*>(ptrFloat);
                cout << i << " Double Val: " << *ptrDouble << endl;
                colorMapRTI_1->data()->cellToCoord(i, 0, &x, &y);
                colorMapRTI_1->data()->setCell(i, 0, *ptrDouble);
                ptrFloat++;
            }
            ui->rti_1->replot();
            colorMapRTI_1->rescaleDataRange();
        } // end of while
    

    Thanks everyone.



  • @Renegade243
    Your code is always reading the first 4 bytes
    And

    const double* ptrDouble = reinterpret_cast<const double*>(ptrFloat);
    

    is definitely wrong in this case. Should change that to

        while(tcpClient.bytesAvailable()){
            data_in = tcpClient.read(PayloadSize); // 2048 samples
            int numSamples = data_in.size() / 4;
            const float* ptrFloat = reinterpret_cast<const float*>(data_in.constData());
            for (int i=0; i<numSamples; ++i){
                cout << i << " Float Val: " << *ptrFloat << endl;
                double readDouble = *ptrFloat ;
                cout << i << " Double Val: " << readDouble << endl;
                colorMapRTI_1->data()->cellToCoord(i, 0, &x, &y);
                colorMapRTI_1->data()->setCell(i, 0, readDouble);
                ptrFloat++;
            }
            ui->rti_1->replot();
            colorMapRTI_1->rescaleDataRange();
        } // end of while
    


  • Hi @Bonnie,

    Thank you so much this did the trick, sorry for the late reply I was having fun playing with the streaming. This is really amazing thank you so much :)

    Best Regards, Ren


Log in to reply