1function s=compressShape(w, forceCompression)
2%compressShape Compress a gradient or pulse shape.
3% s=compressShape(w) Compress the waveform using a run-length compression
4% scheme on the derivative. This strategy encodes constant and linear
5% waveforms with very few samples. A structure is returned with the
6% fields:
7% num_samples - the number of samples in the uncompressed waveform
8% data - containing the compressed waveform
9%
10% See also decompressShape
12if nargin<2
13 forceCompression=false;
14end
16if any(~isfinite(w))
17 error('compressShape() received infinite samples');
18end
20if ~forceCompression && length(w) <= 4 % avoid compressing very short shapes
21 s.num_samples=length(w);
22 s.data = w(:)';
23 return;
24end
27% %MZ: old code with implicit quantization
28% data = [w(1); diff(w(:))];
29% maskChanges = [true; abs(diff(data))>1e-8]; % TRUE if values change
30% vals = data(maskChanges); % Elements without repetitions
32% MZ: explicit quantization with error correction
33quant_fac=1e-7; % single precision floating point has ~7.25 decimal places
34ws=w./quant_fac;
35datq=round([ws(1); diff(ws(:))]);
36qerr=ws(:)-cumsum(datq);
37qcor=[0; diff(round(qerr))];
38datd=datq+qcor;
39maskChanges=[true; diff(datd)~=0];
40vals=datd(maskChanges).*quant_fac; % Elements without repetitions
42k = find([maskChanges', true]); % Indices of changes
43n = diff(k)'; % Number of repetitions
45% Encode in Pulseq format
46nExtra=n-2;
47vals2=vals;
48vals2(nExtra<0)=nan;
49nExtra(nExtra<0)=nan;
50v=[vals vals2 nExtra]';
51v=v(isfinite(v));
52v(abs(v)<1e-10)=0;
53s.num_samples = length(w);
54% decide whether compression makes sense, otherwise store the original
55if forceCompression || s.num_samples > length(v)
56 s.data = v';
57else
58 s.data = w(:)';
59end