Task 522: .PCS File Format

Task 522: .PCS File Format

File Format Specifications for .PCS

The .PCS file format is a custom, text-based format used by Pico Technology for storing oscilloscope data from multiple channels. It consolidates data from multiple CSV files into a single file, allowing for processing of samples with relative time shifts. The format is line-based, with each line representing a time bin for a specific channel. Fields are space-separated, and lines are newline-separated. The first field combines the channel number and delta-t (time interval in ns). Subsequent fields are sample values.

  1. List of all the properties of this file format intrinsic to its file system:
  • Channel number: An integer indicating the channel (e.g., 0 for A, 1 for B, etc.), derived from the integer part of the first field on each line.
  • Delta-T: A floating-point value representing the time interval in nanoseconds for that bin, derived from the fractional part of the first field on each line.
  • Sample values: A list of floating-point numbers representing the sample data for that channel in the bin, consisting of all subsequent fields on the line.
  1. Two direct download links for files of format .PCS.

No public .PCS files were found available for direct download during the search. The forum post references an example file "20210823-0004.pcs" but it is not hosted or linked for download.

  1. Ghost blog embedded html javascript that allows a user to drag n drop a file of format .PCS and it will dump to screen all these properties.
PCS File Parser
Drag and drop .PCS file here
  1. Python class that can open any file of format .PCS and decode read and write and print to console all the properties from the above list.
class PcsFile:
    def __init__(self, filename):
        self.filename = filename
        self.data = []  # List of tuples: (channel, delta_t, samples)

    def read(self):
        with open(self.filename, 'r') as f:
            lines = f.readlines()
        for line in lines:
            fields = line.strip().split()
            if fields:
                first = float(fields[0])
                channel = int(first)
                delta_t = first - channel
                samples = [float(s) for s in fields[1:]]
                self.data.append((channel, delta_t, samples))

    def print_properties(self):
        for channel, delta_t, samples in self.data:
            print(f"Channel: {channel}, Delta-T: {delta_t} ns, Samples: {samples}")

    def write(self):
        with open(self.filename, 'w') as f:
            for channel, delta_t, samples in self.data:
                first = channel + delta_t
                line = f"{first:.2f} " + " ".join(f"{s:.6f}" for s in samples) + "\n"
                f.write(line)

# Example usage:
# pcs = PcsFile('example.pcs')
# pcs.read()
# pcs.print_properties()
# # To write, modify pcs.data and call pcs.write()
  1. Java class that can open any file of format .PCS and decode read and write and print to console all the properties from the above list.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;

public class PcsFile {
    private String filename;
    private List<double[]> data = new ArrayList<>(); // Each array: [channel, delta_t, samples...]

    public PcsFile(String filename) {
        this.filename = filename;
    }

    public void read() throws Exception {
        data.clear();
        try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
            String line;
            while (line = br.readLine() != null) {
                String[] fields = line.trim().split("\\s+");
                if (fields.length > 0) {
                    double first = Double.parseDouble(fields[0]);
                    int channel = (int) first;
                    double deltaT = first - channel;
                    double[] samples = new double[fields.length - 1];
                    for (int i = 1; i < fields.length; i++) {
                        samples[i - 1] = Double.parseDouble(fields[i]);
                    }
                    double[] entry = new double[samples.length + 2];
                    entry[0] = channel;
                    entry[1] = deltaT;
                    System.arraycopy(samples, 0, entry, 2, samples.length);
                    data.add(entry);
                }
            }
        }
    }

    public void printProperties() {
        for (double[] entry : data) {
            int channel = (int) entry[0];
            double deltaT = entry[1];
            double[] samples = Arrays.copyOfRange(entry, 2, entry.length);
            System.out.println("Channel: " + channel + ", Delta-T: " + deltaT + " ns, Samples: " + Arrays.toString(samples));
        }
    }

    public void write() throws Exception {
        try (PrintWriter pw = new PrintWriter(filename)) {
            for (double[] entry : data) {
                int channel = (int) entry[0];
                double deltaT = entry[1];
                double first = channel + deltaT;
                pw.print(String.format("%.2f ", first));
                for (int i = 2; i < entry.length; i++) {
                    pw.print(String.format("%.6f ", entry[i]));
                }
                pw.println();
            }
        }
    }

    // Example usage:
    // public static void main(String[] args) throws Exception {
    //     PcsFile pcs = new PcsFile("example.pcs");
    //     pcs.read();
    //     pcs.printProperties();
    //     // To write, modify pcs.data and call pcs.write()
    // }
}
  1. Javascript class that can open any file of format .PCS and decode read and write and print to console all the properties from the above list.
const fs = require('fs'); // For Node.js

class PcsFile {
    constructor(filename) {
        this.filename = filename;
        this.data = []; // Array of objects: {channel, deltaT, samples}
    }

    read() {
        const text = fs.readFileSync(this.filename, 'utf8');
        const lines = text.split('\n');
        this.data = [];
        lines.forEach(line => {
            const fields = line.trim().split(/\s+/);
            if (fields.length > 0 && !isNaN(parseFloat(fields[0]))) {
                const first = parseFloat(fields[0]);
                const channel = Math.floor(first);
                const deltaT = first - channel;
                const samples = fields.slice(1).map(parseFloat);
                this.data.push({channel, deltaT, samples});
            }
        });
    }

    printProperties() {
        this.data.forEach(entry => {
            console.log(`Channel: ${entry.channel}, Delta-T: ${entry.deltaT} ns, Samples: [${entry.samples.join(', ')}]`);
        });
    }

    write() {
        let content = '';
        this.data.forEach(entry => {
            const first = entry.channel + entry.deltaT;
            content += `${first.toFixed(2)} ${entry.samples.map(s => s.toFixed(6)).join(' ')}\n`;
        });
        fs.writeFileSync(this.filename, content);
    }
}

// Example usage:
// const pcs = new PcsFile('example.pcs');
// pcs.read();
// pcs.printProperties();
// // To write, modify pcs.data and call pcs.write()
  1. C class that can open any file of format .PCS and decode read and write and print to console all the properties from the above list.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define MAX_LINE 1024
#define MAX_SAMPLES 1000 // Arbitrary max per line

struct PcsEntry {
    int channel;
    double delta_t;
    double *samples;
    int num_samples;
};

struct PcsFile {
    char *filename;
    struct PcsEntry *entries;
    int num_entries;
};

struct PcsFile *pcs_create(const char *filename) {
    struct PcsFile *pcs = malloc(sizeof(struct PcsFile));
    pcs->filename = strdup(filename);
    pcs->entries = NULL;
    pcs->num_entries = 0;
    return pcs;
}

void pcs_read(struct PcsFile *pcs) {
    FILE *f = fopen(pcs->filename, "r");
    if (!f) return;

    char line[MAX_LINE];
    while (fgets(line, MAX_LINE, f)) {
        char *token = strtok(line, " \t\n");
        if (token) {
            double first = atof(token);
            int channel = floor(first);
            double delta_t = first - channel;
            struct PcsEntry entry;
            entry.channel = channel;
            entry.delta_t = delta_t;
            entry.samples = malloc(sizeof(double) * MAX_SAMPLES);
            entry.num_samples = 0;
            while ((token = strtok(NULL, " \t\n")) && entry.num_samples < MAX_SAMPLES) {
                entry.samples[entry.num_samples++] = atof(token);
            }
            pcs->entries = realloc(pcs->entries, sizeof(struct PcsEntry) * (pcs->num_entries + 1));
            pcs->entries[pcs->num_entries++] = entry;
        }
    }
    fclose(f);
}

void pcs_print_properties(struct PcsFile *pcs) {
    for (int i = 0; i < pcs->num_entries; i++) {
        struct PcsEntry entry = pcs->entries[i];
        printf("Channel: %d, Delta-T: %.2f ns, Samples: [", entry.channel, entry.delta_t);
        for (int j = 0; j < entry.num_samples; j++) {
            printf("%.6f", entry.samples[j]);
            if (j < entry.num_samples - 1) printf(", ");
        }
        printf("]\n");
    }
}

void pcs_write(struct PcsFile *pcs) {
    FILE *f = fopen(pcs->filename, "w");
    if (!f) return;

    for (int i = 0; i < pcs->num_entries; i++) {
        struct PcsEntry entry = pcs->entries[i];
        double first = entry.channel + entry.delta_t;
        fprintf(f, "%.2f ", first);
        for (int j = 0; j < entry.num_samples; j++) {
            fprintf(f, "%.6f ", entry.samples[j]);
        }
        fprintf(f, "\n");
    }
    fclose(f);
}

void pcs_destroy(struct PcsFile *pcs) {
    for (int i = 0; i < pcs->num_entries; i++) {
        free(pcs->entries[i].samples);
    }
    free(pcs->entries);
    free(pcs->filename);
    free(pcs);
}

// Example usage:
// int main() {
//     struct PcsFile *pcs = pcs_create("example.pcs");
//     pcs_read(pcs);
//     pcs_print_properties(pcs);
//     // To write, modify pcs->entries and call pcs_write(pcs);
//     pcs_destroy(pcs);
//     return 0;
// }