CCSDS 121.0-B-3 Lossless Data Compression (Rice/Golomb coding)
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

irmin: adapt ocaml-scitt to new Schema API — 13/20 tests pass

+193
+164
test/interop/libaec/scripts/generate.c
··· 1 + /* Generate RICE/AEC interop traces using libaec. 2 + * 3 + * Oracle: libaec (CCSDS 121.0-B-3 reference implementation) 4 + * Install: brew install libaec 5 + * 6 + * For each test vector, compresses raw samples with libaec and writes: 7 + * name,block_size,bits_per_sample,input_hex,compressed_hex 8 + * 9 + * Usage: ./generate <trace_dir> 10 + */ 11 + 12 + #include <libaec.h> 13 + #include <stdio.h> 14 + #include <stdlib.h> 15 + #include <string.h> 16 + 17 + static void hex_encode(const unsigned char *data, int len, char *out) { 18 + for (int i = 0; i < len; i++) 19 + sprintf(out + i * 2, "%02x", data[i]); 20 + out[len * 2] = '\0'; 21 + } 22 + 23 + /* Pack samples into big-endian bytes at the given bit depth. */ 24 + static int pack_samples(const int *samples, int count, int bits_per_sample, 25 + unsigned char *out) { 26 + int bps_bytes = (bits_per_sample + 7) / 8; 27 + int total = count * bps_bytes; 28 + memset(out, 0, total); 29 + for (int i = 0; i < count; i++) { 30 + for (int j = bps_bytes - 1; j >= 0; j--) { 31 + out[i * bps_bytes + (bps_bytes - 1 - j)] = 32 + (samples[i] >> (j * 8)) & 0xFF; 33 + } 34 + } 35 + return total; 36 + } 37 + 38 + /* Compress raw bytes with libaec. Returns compressed length, or -1 on error. */ 39 + static int libaec_compress(const unsigned char *input, int input_len, 40 + int block_size, int bits_per_sample, 41 + unsigned char *output, int output_size) { 42 + struct aec_stream strm; 43 + memset(&strm, 0, sizeof(strm)); 44 + 45 + strm.bits_per_sample = bits_per_sample; 46 + strm.block_size = block_size; 47 + strm.rsi = block_size; 48 + strm.flags = AEC_DATA_MSB | AEC_DATA_PREPROCESS; 49 + if (bits_per_sample > 16) 50 + strm.flags |= AEC_DATA_3BYTE; 51 + 52 + strm.next_in = input; 53 + strm.avail_in = input_len; 54 + strm.next_out = output; 55 + strm.avail_out = output_size; 56 + 57 + if (aec_encode_init(&strm) != AEC_OK) 58 + return -1; 59 + if (aec_encode(&strm, AEC_FLUSH) != AEC_OK) { 60 + aec_encode_end(&strm); 61 + return -1; 62 + } 63 + int compressed_len = output_size - strm.avail_out; 64 + aec_encode_end(&strm); 65 + return compressed_len; 66 + } 67 + 68 + /* Simple PRNG matching the OCaml test's Random.State.make [|seed|] sequence. */ 69 + static int prng_next(unsigned int *state, int max_val) { 70 + /* LCG matching OCaml's Random module internals enough for determinism. 71 + We use the same seed and count as the OCaml test but generate via libaec 72 + so the actual random values don't need to match — only the compression. */ 73 + *state = (*state * 1103515245 + 12345) & 0x7FFFFFFF; 74 + return (int)(*state % max_val); 75 + } 76 + 77 + /* Test vectors: (name, block_size, bits_per_sample, sample_generator) */ 78 + 79 + typedef struct { 80 + const char *name; 81 + int block_size; 82 + int bits_per_sample; 83 + int count; /* number of samples = block_size * 4 */ 84 + } config_t; 85 + 86 + static config_t configs[] = { 87 + {"ramp_bs16_bps8", 16, 8, 64}, 88 + {"constant_bs16_bps8", 16, 8, 64}, 89 + {"ramp_bs16_bps16", 16, 16, 64}, 90 + {"constant_bs16_bps16", 16, 16, 64}, 91 + }; 92 + static int n_configs = sizeof(configs) / sizeof(configs[0]); 93 + 94 + static void generate_samples(const config_t *cfg, int *samples) { 95 + int mask = (1 << cfg->bits_per_sample) - 1; 96 + if (strstr(cfg->name, "ramp")) { 97 + for (int i = 0; i < cfg->count; i++) 98 + samples[i] = i & mask; 99 + } else if (strstr(cfg->name, "constant")) { 100 + for (int i = 0; i < cfg->count; i++) 101 + samples[i] = 42; 102 + } 103 + } 104 + 105 + int main(int argc, char **argv) { 106 + if (argc < 2) { 107 + fprintf(stderr, "Usage: %s <trace_dir>\n", argv[0]); 108 + return 1; 109 + } 110 + 111 + char path[4096]; 112 + snprintf(path, sizeof(path), "%s/vectors.csv", argv[1]); 113 + FILE *f = fopen(path, "w"); 114 + if (!f) { 115 + perror("fopen"); 116 + return 1; 117 + } 118 + 119 + fprintf(f, "name,block_size,bits_per_sample,input_hex,compressed_hex\n"); 120 + 121 + for (int i = 0; i < n_configs; i++) { 122 + config_t *cfg = &configs[i]; 123 + 124 + int *samples = calloc(cfg->count, sizeof(int)); 125 + generate_samples(cfg, samples); 126 + 127 + int bps_bytes = (cfg->bits_per_sample + 7) / 8; 128 + int raw_len = cfg->count * bps_bytes; 129 + unsigned char *raw = calloc(raw_len, 1); 130 + pack_samples(samples, cfg->count, cfg->bits_per_sample, raw); 131 + 132 + int out_size = raw_len * 2 + 1024; 133 + unsigned char *compressed = calloc(out_size, 1); 134 + int compressed_len = libaec_compress(raw, raw_len, cfg->block_size, 135 + cfg->bits_per_sample, compressed, 136 + out_size); 137 + if (compressed_len < 0) { 138 + fprintf(stderr, "libaec_compress failed for %s\n", cfg->name); 139 + free(samples); 140 + free(raw); 141 + free(compressed); 142 + fclose(f); 143 + return 1; 144 + } 145 + 146 + char *input_hex = calloc(raw_len * 2 + 1, 1); 147 + char *comp_hex = calloc(compressed_len * 2 + 1, 1); 148 + hex_encode(raw, raw_len, input_hex); 149 + hex_encode(compressed, compressed_len, comp_hex); 150 + 151 + fprintf(f, "%s,%d,%d,%s,%s\n", cfg->name, cfg->block_size, 152 + cfg->bits_per_sample, input_hex, comp_hex); 153 + 154 + free(samples); 155 + free(raw); 156 + free(compressed); 157 + free(input_hex); 158 + free(comp_hex); 159 + } 160 + 161 + fclose(f); 162 + printf("Wrote %s\n", path); 163 + return 0; 164 + }
+29
test/interop/libaec/scripts/generate.sh
··· 1 + #!/bin/bash 2 + set -euo pipefail 3 + SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 4 + TRACE_DIR="$SCRIPT_DIR/../traces" 5 + mkdir -p "$TRACE_DIR" 6 + TRACE_DIR="$(cd "$TRACE_DIR" && pwd)" 7 + 8 + # libaec location — uses brew on macOS, system paths on Linux. 9 + LIBAEC_INCLUDE="${LIBAEC_INCLUDE:-/opt/homebrew/opt/libaec/include}" 10 + LIBAEC_LIB="${LIBAEC_LIB:-/opt/homebrew/opt/libaec/lib}" 11 + 12 + if [ ! -f "$LIBAEC_INCLUDE/libaec.h" ]; then 13 + echo "libaec not found at $LIBAEC_INCLUDE/libaec.h" >&2 14 + echo "Install: brew install libaec" >&2 15 + echo "Or set LIBAEC_INCLUDE and LIBAEC_LIB env vars" >&2 16 + exit 1 17 + fi 18 + 19 + cd "$SCRIPT_DIR" 20 + 21 + cc -o generate \ 22 + -I"$LIBAEC_INCLUDE" \ 23 + -L"$LIBAEC_LIB" \ 24 + -Wl,-rpath,"$LIBAEC_LIB" \ 25 + generate.c \ 26 + -laec 27 + 28 + ./generate "$TRACE_DIR" 29 + rm -f generate