Najlepsze kodowanie będzie w dużej mierze zależeć od dystrybucji próbek. Powiedziałeś nam, że delty są w większości dość małe, co oznacza, że pierwszym krokiem będzie prawie na pewno kodowanie delta (przekształcenie każdej wartości w jej różnicę w stosunku do poprzedniej wartości).
Kolejnym ograniczeniem będzie system, w którym wykonujesz kodowanie - powiedziałeś, że jest „osadzony”, ale obejmuje to całkiem szeroki zakres możliwości. Powiedziałeś również, że karty SD są poza zakresem i że buforujesz tylko 450 próbek naraz w pamięci RAM, co sugeruje naprawdę bardzo mały system. W takim przypadku optymalizacja pod kątem prostoty i oszczędzania procesora / pamięci RAM wydaje się odpowiednia.
Jeśli najczęstszą wartością delta jest dokładnie 0 - to znaczy, że partie próbek są takie same jak poprzednia próbka - prawdopodobnie dobrym pomysłem jest najpierw „zakodowanie długości serii” te serie wartości 0. (Tj. Po prostu zapisywanie, ile było ich w rzędzie.)
Reszta zależy dalej od tego, jak wygląda rozkład wartości. Zakładam dla celów ćwiczeń, że prawie wszystkie są w zakresie -64 < x < 63 (tj. 7-bitowa liczba całkowita ze znakiem). Zakładam również, że najłatwiej jest pracować z bajtami, a nie bitami (co prawdopodobnie jest prawdą, jeśli np. Piszesz C) - jeśli to nie jest prawda, zobacz sam dół odpowiedzi dla schematu bitowego. Bardzo proste kodowanie bajtowe mogłoby wyglądać mniej więcej tak:
0b0xxxxxxx
- wartość literału (delta) reprezentowana jako 7-bitowa liczba całkowita ze znakiem w części „xxxxxxx”. (Wartości od -64 do 63.)
0b10xxxxxx
- ciąg zer (delt) o długości reprezentowanej przez "xxxxxx" (6 bitów bez znaku może wyrazić do 63, a jeśli potrzebujemy więcej, możemy po prostu dodać kolejny wpis.)
0b110xxxxx 0byyyyyyyy
- wartość literału (delta) reprezentowana jako 13-bitowa liczba całkowita ze znakiem w części „xxxxxyyyyyyyy”.
0b11111111 0bxxxxxxxx 0byyyyyyyy
- wartość literału (delta) reprezentowana jako 16-bitowa liczba całkowita ze znakiem. Jest to bardzo nieefektywne kodowanie (oczywiście), ponieważ zamienia 16-bitową wartość na 3-bajtową reprezentację. To niepotrzebnie marnuje miejsce, aby utrzymać wyrównanie bajtów wyjściowych. Ten schemat ma sens tylko wtedy, gdy tak duże delty są bardzo rzadkie. (Każdy nietrywialny schemat kompresji będzie miał pewne dane wejściowe, dla których wynikowe wyjście jest faktycznie większe; to jest twierdzenie teorii informacji.)
(Powyższy schemat jest nieco inspirowany kodowaniem UTF-8 w Unicode.)
W przeciwieństwie do kodów Huffmana (wymienionych w innej odpowiedzi), zakładany rozkład wartości jest ustalany z góry. Jest to zaleta, ponieważ sprawia, że wszystko jest proste i pozwala uniknąć dodawania narzutu na początku każdego bloku sampli; to wada, ponieważ bardziej adaptacyjny schemat nie wymagałby ręcznego dostrajania dystrybucji.
Jeśli delty znacznie mniejsze niż -64 do 63 są powszechne, lepsze kodowanie bajtowe niż powyższe będzie wymagało przetworzenia więcej niż jednej próbki na raz, aby uzyskać kompresję lepszą niż 2: 1 (to znaczy więcej niż jedna próbka na bajt wyjściowy.)
Jeśli kodowanie bitowe jest w porządku, znacznie prostszy do opisania schemat jest następujący: nadal najpierw kodowanie delta, a następnie kodowanie w następujący sposób. Po bitu 0 następuje dodatnia liczba całkowita o zmiennej długości, kodująca liczbę następnych zer; po bitu 1 następuje bit znaku, a następnie dodatnia liczba całkowita o zmiennej długości, razem kodując następną wartość (delta). Dodatnie liczby całkowite o zmiennej długości mogą być zakodowane przy użyciu jednego z kodów z https://en.wikipedia.org/wiki/Universal_code_(data_compression), takiego jak jeden z kodów Eliasa. (To, które kodowanie jest najlepsze, znowu będzie zależeć od dystrybucji danych, ale prawdopodobnie każde z nich będzie świetne).