Flow Cytometry FCS file data segment, linear data seems distorted

final and last update (I promise)

The core of the problem is data movement, as Jonathan Leffler mentioned. Binary data is "located" in the matrix. For example, if I have 3 events and 4 parameters of a bit width of 8, binary data

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

will look like

00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 00

I have two for loops i and j, and I need to calculate the offset using this.

I originally had

(i * PAR * 2) + (j * PnB/8)

Where PAR is the number of parameters, PnB is the bit width, and I is from 0 to full events, and j is from 0 to PAR. This is incorrect, and I'm not sure how I got this formula.

==

, . FCS, , FACSCaliber MacOS 9 CellQuest. FSC-H SSC-H, , ( FlowJo). , , MacOS 9 CellQuest, , :

for (int i = 0; i < params[j-1].PnB/8; ++i)
{
    lebyte[i] = (bytes[(params[j-1].PnB/8)-1-i] & 0xff) << i*8u;
    cx |= lebyte[i];
}

, , , , .

PnB - PnR -

, , , , PnR, PnR = 1024, , 16- , 0 - 1023.

, , , FSC-H x.

FCS 3.1 ( , , . 13):

$BYTEORD/n1, n2, n3, n4/$BYTEORD/4,3,2,1/[]

, , . {1} {4}, , 32- . (ASCII 44). :

  • $BYTEORD/1,2,3,4/( , , , , x86)

  • $BYTEORD/4,3,2,1/( , , , , PowerPC, Apple Macintosh, Intel) , 32 ($ DATATYPE/D/)

, . .

. 1

Skewed SCC-H x FSC-H

2

endian .

#include <stdio.h>
#include <stdlib.h>

int main() {
    int PnB = 16; // bitwidth of data stored for a specific channel value
    // for example the data value for sample A is stored in 16 bits.
    char bytes[PnB/8];
    unsigned int lebyte[PnB/8];
    unsigned int cx = 0;

    unsigned int b0, b1;

    /*  |  [0] |  [1] |
    *  | 0xff | 0x03 |
    */
    bytes[1] = 0x03;
    bytes[0] = 0xff;

    // in big endian print out

    b0 = (bytes[0] & 0xff) << 8u;
    b1 = bytes[1] & 0xff;

    cx = b0 | b1;

    printf("%d\n", cx);

    cx = 0;

    // convert to little endian

    for (int i = 0; i < PnB/8; ++i)
    {
        lebyte[i] = (bytes[i] & 0xff) << i*8u;
        cx |= lebyte[i];
    }

    printf("%d\n", cx);
}

:

65283

1023

, (, , ).

, memcpy .

memset(bytes, '\0', sizeof(char)*params[j-1].PnB/8);
memcpy(bytes, databuf+((i*data->PAR*2)+(j*params[j-1].PnB/8)), params[j-1].PnB/8);

. , . - , , FlowJo ;). , .

3

, , :

typedef struct _fcs_parameter {
    double f1;          // logarithmic decade
    double f2;          // minimum value on log scale
    unsigned int PnB;   // bitwidth
    unsigned int PnR;   // range
    fcs_events *events; // event data
    char *sname;        // short name
    char *lname;        // filter name
} fcs_parameter;
+3
2

, .

:

for (int i = 0; i < data->TOT; ++i)
    {
        for (int j = 0; j < data->PAR; ++j)
        {

        // code removed for brevity

        memset(bytes, '\0', sizeof(char)*params[j].PnB/8);
        memcpy(bytes, databuf+((i*data->PAR*params[j].PnB/8)+(j*params[j].PnB/8)), params[j].PnB/8);

        // more code here
        }
}

! , , , PnB.

0

memset() memcpy(), . , i, params, . , PnB, , memcpy() .

; . memset/memcpy, , , . , , -, .

static inline, C99. , C99. C89, .

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static uint16_t convert_uint16be(uint8_t const *bytes)
{
    uint16_t r = (bytes[0] << 8) | bytes[1];
    return r;
}

static uint32_t convert_uint32be(uint8_t const *bytes)
{
    uint32_t r = (((((bytes[0] << 8) | bytes[1]) << 8) | bytes[2]) << 8) | bytes[3];
    return r;
}

static void print16(uint8_t const *bytes)
{
  uint16_t r1 = convert_uint16be(bytes);
  int16_t  r2 = convert_uint16be(bytes);
  printf("0x%.2X 0x%.2X = 0x%.4" PRIX16 " = %6" PRId16 "\n", bytes[0], bytes[1], r1, r2);
}

static void print32(uint8_t const *bytes)
{
  uint32_t r1 = convert_uint32be(bytes);
  int32_t  r2 = convert_uint32be(bytes);
  printf("0x%.2X 0x%.2X 0x%.2X 0x%.2X = 0x%.8" PRIX32 " = %11" PRId32 "\n", bytes[0], bytes[1], bytes[2], bytes[3], r1, r2);
}

int main(void)
{
    int PnB = 16; // bitwidth of data stored for a specific channel value
    // for example the data value for sample A is stored in 16 bits.
    char bytes[PnB/8];
    unsigned int lebyte[PnB/8];
    unsigned int cx = 0;
    unsigned int b0, b1;

    /*  |  [0] |  [1] |
     *  | 0xff | 0x03 |
     */
    bytes[0] = 0xff;
    bytes[1] = 0x03;

    // in big endian print out
    b0 = (bytes[0] & 0xff) << 8u;
    b1 = bytes[1] & 0xff;
    cx = b0 | b1;

    printf("%5d = 0x%.4X\n", cx, cx);

    // convert to little endian
    cx = 0;
    for (int i = 0; i < PnB/8; ++i)
    {
        lebyte[i] = (bytes[i] & 0xff) << i*8u;
        cx |= lebyte[i];
    }
    printf("%5d = 0x%.4X\n", cx, cx);

    print16((uint8_t *)bytes);

    uint8_t data[] =
    {
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x03, 0xFF,
      0x00, 0x00, 0xFF, 0xFF,
      0x08, 0x08, 0x09, 0xC0,
      0x80, 0x80, 0x90, 0x0C,
      0xFF, 0xFF, 0xED, 0xBC,
    };
    int data_size = sizeof(data) / sizeof(data[0]);

    for (int i = 0; i < data_size; i += 2)
      print16(&data[i]);
    for (int i = 0; i < data_size; i += 4)
      print32(&data[i]);

    {
      struct { int PnB; } params[] = { { 16 }, { 16 }, { 32 }, { 16 }, { 16 }, };
      int num_params = sizeof(params) / sizeof(params[0]);
      uint8_t value[4];
      int i = 0;
      int num = num_params;
      int offset = 0;
      for (int j = 1; j <= num; j++)
      {
        memset(value, '\0', sizeof(char)*params[j-1].PnB/8);
        printf("i = %2d; j = %2d; offset = %2d; calc = %2d; size = %2d\n",
               i, j, offset, ((i*7*2)+(j*params[j-1].PnB/8)), params[j-1].PnB/8);
        /* The calculation works plausibly when all params[n].PnB are the same
         * size, but not otherwise
         */
        memcpy(value, data+((i*7*2)+(j*params[j-1].PnB/8)), params[j-1].PnB/8);
        if (params[j].PnB == 16)
          print16(value);
        else
          print32(value);
        memcpy(value, data+offset, params[j-1].PnB/8);
        if (params[j].PnB == 16)
          print16(value);
        else
          print32(value);
        offset += params[j-1].PnB/8;
      }
    }

    return 0;
}

:

65283 = 0xFF03
 1023 = 0x03FF
0xFF 0x03 = 0xFF03 =   -253
0x00 0x00 = 0x0000 =      0
0x00 0x00 = 0x0000 =      0
0x00 0x00 = 0x0000 =      0
0x03 0xFF = 0x03FF =   1023
0x00 0x00 = 0x0000 =      0
0xFF 0xFF = 0xFFFF =     -1
0x08 0x08 = 0x0808 =   2056
0x09 0xC0 = 0x09C0 =   2496
0x80 0x80 = 0x8080 = -32640
0x90 0x0C = 0x900C = -28660
0xFF 0xFF = 0xFFFF =     -1
0xED 0xBC = 0xEDBC =  -4676
0x00 0x00 0x00 0x00 = 0x00000000 =           0
0x00 0x00 0x03 0xFF = 0x000003FF =        1023
0x00 0x00 0xFF 0xFF = 0x0000FFFF =       65535
0x08 0x08 0x09 0xC0 = 0x080809C0 =   134744512
0x80 0x80 0x90 0x0C = 0x8080900C = -2139058164
0xFF 0xFF 0xED 0xBC = 0xFFFFEDBC =       -4676
i =  0; j =  1; offset =  0; calc =  2; size =  2
0x00 0x00 = 0x0000 =      0
0x00 0x00 = 0x0000 =      0
i =  0; j =  2; offset =  2; calc =  4; size =  2
0x00 0x00 0x00 0x00 = 0x00000000 =           0
0x00 0x00 0x00 0x00 = 0x00000000 =           0
i =  0; j =  3; offset =  4; calc = 12; size =  4
0x08 0x08 = 0x0808 =   2056
0x00 0x00 = 0x0000 =      0
i =  0; j =  4; offset =  8; calc =  8; size =  2
0x00 0x00 = 0x0000 =      0
0x00 0x00 = 0x0000 =      0
i =  0; j =  5; offset = 10; calc = 10; size =  2
0xFF 0xFF 0x03 0xFF = 0xFFFF03FF =      -64513
0xFF 0xFF 0x03 0xFF = 0xFFFF03FF =      -64513
+1

All Articles