edfcore 0.6.22 → 0.6.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/format-header.d.ts.map +1 -1
- package/dist/format-header.js +41 -3
- package/dist/format-header.js.map +1 -1
- package/docs/CHANGELOG.md +41 -0
- package/package.json +1 -1
- package/src/constants.ts +1 -1
- package/src/format-header.ts +41 -3
package/dist/constants.d.ts
CHANGED
|
@@ -109,5 +109,5 @@ export declare const SIGNAL_FIELD_BLOCK_OFFSETS: {
|
|
|
109
109
|
readonly reserved: 224;
|
|
110
110
|
};
|
|
111
111
|
/** Published package version. Kept in sync with package.json by a test. */
|
|
112
|
-
export declare const VERSION = "0.6.
|
|
112
|
+
export declare const VERSION = "0.6.24";
|
|
113
113
|
//# sourceMappingURL=constants.d.ts.map
|
package/dist/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-header.d.ts","sourceRoot":"","sources":["../src/format-header.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAQH,OAAO,KAAK,EAAmB,SAAS,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"format-header.d.ts","sourceRoot":"","sources":["../src/format-header.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAQH,OAAO,KAAK,EAAmB,SAAS,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAsElF;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,MAAM,CA4IrF"}
|
package/dist/format-header.js
CHANGED
|
@@ -53,9 +53,36 @@ function dimensionSuffix(signal) {
|
|
|
53
53
|
const dimension = printable(signal.physicalDimension);
|
|
54
54
|
return dimension === '' ? '' : ` ${dimension}`;
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* The rate for the table, rounded when the exact value would not fit in a column.
|
|
58
|
+
*
|
|
59
|
+
* `sampleRateHz` is `samplesPerRecord / recordDurationSeconds`, and that division does not have to
|
|
60
|
+
* come out. A 0.29 s record holding 20 samples is 68.96551724137932 Hz, and interpolating it raw
|
|
61
|
+
* put seventeen digits into a nine-character column — pushing `range` off its position on that row
|
|
62
|
+
* alone, which is the alignment `formatHeader` was fixed for once already in 0.3.96, arriving by a
|
|
63
|
+
* different route. It also stated a derived quotient to the last bit of a float64, in a table whose
|
|
64
|
+
* other numbers are what the file says.
|
|
65
|
+
*
|
|
66
|
+
* `~` rather than a silently rounded number, because this module promises never to invent a value.
|
|
67
|
+
* The exact rate is on `signal.sampleRateHz`, `edfcore signals` prints it unrounded for scripts,
|
|
68
|
+
* and `samplesPerRecord` is the authoritative field either way — `cli.md` says to index by that and
|
|
69
|
+
* never by the rate.
|
|
70
|
+
*
|
|
71
|
+
* A rate whose exact spelling already fits is printed exactly, so the ordinary file is unchanged
|
|
72
|
+
* and the tilde means something when it appears. A rate too small to survive two decimal places
|
|
73
|
+
* falls back to the exact value rather than printing `~0 Hz`, which would be a claim rather than a
|
|
74
|
+
* rounding.
|
|
75
|
+
*/
|
|
56
76
|
function formatRate(signal) {
|
|
77
|
+
const rate = signal.sampleRateHz;
|
|
57
78
|
// undefined is the honest answer for a zero record duration, which is legal EDF.
|
|
58
|
-
|
|
79
|
+
if (rate === undefined)
|
|
80
|
+
return '—';
|
|
81
|
+
const exact = `${rate}`;
|
|
82
|
+
if (exact.length <= 6)
|
|
83
|
+
return `${exact} Hz`;
|
|
84
|
+
const rounded = Number(rate.toFixed(2));
|
|
85
|
+
return rounded === 0 ? `${exact} Hz` : `~${rounded} Hz`;
|
|
59
86
|
}
|
|
60
87
|
/**
|
|
61
88
|
* A multi-line summary of a header.
|
|
@@ -125,13 +152,24 @@ export function formatHeader(header, options) {
|
|
|
125
152
|
lines.push(`recording ${printable(trimEdfField(header.recording.raw)) || 'unknown'}`);
|
|
126
153
|
}
|
|
127
154
|
lines.push('');
|
|
155
|
+
/*
|
|
156
|
+
* Wide enough for the largest index in THIS file, never narrower than the three the heading has
|
|
157
|
+
* always used. EDF's signal-count field is four characters, so 9999 signals is a legal file and
|
|
158
|
+
* a thousand-channel one is an ordinary high-density recording — and a fixed width of three put
|
|
159
|
+
* signal 1000 one column to the right of signal 999, in the middle of the same table. Rows
|
|
160
|
+
* either side of that boundary had their last three columns in different places, which is worse
|
|
161
|
+
* than a table that is uniformly wrong: nothing about it looks like a formatting decision.
|
|
162
|
+
*
|
|
163
|
+
* A file with fewer than a thousand signals prints exactly what it printed before (0.6.24).
|
|
164
|
+
*/
|
|
165
|
+
const indexWidth = Math.max(3, `${Math.max(0, header.signals.length - 1)}`.length);
|
|
128
166
|
// Built from the SAME widths as the data rows below, not spaced by hand. The hand-spaced literal
|
|
129
167
|
// had one space too many after `label` and one after `kind`, so `kind` sat at column 27 over data
|
|
130
168
|
// at 26 and `rate` and `range` were two out — on every file, in the output whose whole purpose is
|
|
131
169
|
// being read in a terminal (fixed in 0.3.96).
|
|
132
|
-
lines.push(
|
|
170
|
+
lines.push(`${'#'.padStart(indexWidth)} ${'label'.padEnd(21)}${'kind'.padEnd(12)}${'rate'.padEnd(9)} range`);
|
|
133
171
|
for (const signal of header.signals) {
|
|
134
|
-
const index = String(signal.index).padStart(
|
|
172
|
+
const index = String(signal.index).padStart(indexWidth);
|
|
135
173
|
// Control characters are replaced, not printed. A label holding a newline would otherwise
|
|
136
174
|
// render as two rows and forge a signal the file does not contain; a tab would shift every
|
|
137
175
|
// column after it. EDF pads labels with spaces and says nothing about what else may be in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-header.js","sourceRoot":"","sources":["../src/format-header.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD;;;;;;;;;GASG;AACH,SAAS,UAAU,CAAC,IAAiC;IACnD,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAAC,KAAa;IACxC,IAAI,KAAK,GAAG,EAAE;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,gBAAgB,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;IACxB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9D,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AACtD,CAAC;AAED,4FAA4F;AAC5F,SAAS,eAAe,CAAC,MAAoC;IAC3D,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACtD,OAAO,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC;AACjD,CAAC;AAED,SAAS,UAAU,CAAC,MAAoC;IACtD,iFAAiF;IACjF,OAAO,
|
|
1
|
+
{"version":3,"file":"format-header.js","sourceRoot":"","sources":["../src/format-header.ts"],"names":[],"mappings":"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"}
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,47 @@ alone does not tell you whether you were affected.
|
|
|
6
6
|
edfcore is pre-1.0. Patch releases have carried behaviour changes where the old behaviour was a
|
|
7
7
|
defect; those are called out below.
|
|
8
8
|
|
|
9
|
+
## 0.6.24
|
|
10
|
+
|
|
11
|
+
- **Fixed** the signal-index column being three characters wide whatever the file, so signal 1000
|
|
12
|
+
sat one column to the right of signal 999 — in the middle of the same table, with the rows either
|
|
13
|
+
side of that boundary putting their last three columns in different places. That is worse than a
|
|
14
|
+
table that is uniformly wrong: nothing about it looks like a formatting decision.
|
|
15
|
+
- EDF's signal-count field is four characters, so 9999 signals is a legal file, and a
|
|
16
|
+
thousand-channel recording is ordinary high-density work rather than a corner case. `inspect.ts`
|
|
17
|
+
already discusses a 512-signal file as the realistic one.
|
|
18
|
+
- The width comes from the largest index in the file and is never narrower than the three it has
|
|
19
|
+
always used, so every file with fewer than a thousand signals prints exactly what it printed
|
|
20
|
+
before. The heading is built from that width rather than spaced by hand, which is the rule 0.3.96
|
|
21
|
+
established for the other four columns.
|
|
22
|
+
- `a-rate-that-does-not-divide.test.ts` now reads the range column off the heading instead of from
|
|
23
|
+
a constant, which is what lets one property cover a width that depends on the file: every row's
|
|
24
|
+
`range` starts where the heading's does, on all thirteen shapes and on a 1200-signal file. The
|
|
25
|
+
0.6.23 rate fix and this one are the same defect in two columns — a value wider than the width it
|
|
26
|
+
was given — and they are checked by the same property now.
|
|
27
|
+
|
|
28
|
+
## 0.6.23
|
|
29
|
+
|
|
30
|
+
- **Fixed** a derived sample rate blowing the column it is printed in. `sampleRateHz` is
|
|
31
|
+
`samplesPerRecord / recordDurationSeconds` and that division does not have to come out: a 0.29 s
|
|
32
|
+
record holding 20 samples is 68.96551724137932 Hz, seventeen digits in a nine-character column.
|
|
33
|
+
`edfcore header` printed it raw, so `range` moved off its position on that row and no other, and
|
|
34
|
+
a reader comparing two rows found the last column of one of them somewhere else.
|
|
35
|
+
- It is the defect 0.3.96 fixed for the heading, arriving by a different route: that one was a
|
|
36
|
+
hand-spaced literal disagreeing with the widths beneath it, this one is a value wider than the
|
|
37
|
+
width. Both make the same table unreadable in the same place.
|
|
38
|
+
- A rate whose exact spelling fits is printed exactly, so the ordinary file is unchanged. One that
|
|
39
|
+
does not is rounded to two decimals and marked `~`, because this module promises never to invent
|
|
40
|
+
a value — and a rate too small to survive two decimals falls back to the exact spelling rather
|
|
41
|
+
than printing `~0 Hz`, which would be a claim rather than a rounding.
|
|
42
|
+
- Nothing a script reads moved. `signal.sampleRateHz` is untouched, `edfcore signals` prints it
|
|
43
|
+
unrounded, `edfcore json` carries it in full, and `samplesPerRecord` is the authoritative field
|
|
44
|
+
either way. A table for a person is the one place four significant figures beat seventeen.
|
|
45
|
+
- `a-rate-that-does-not-divide.test.ts` checks the property rather than the site: every row's
|
|
46
|
+
`range` starts at the same column as every other row's and as the heading's, over all thirteen
|
|
47
|
+
shapes. The matrix only reaches this because 0.6.20 put a 0.29 s record in it — before that every
|
|
48
|
+
shape had a duration of 1 s or 0 s, and every rate was a whole number.
|
|
49
|
+
|
|
9
50
|
## 0.6.22
|
|
10
51
|
|
|
11
52
|
- **Added** the four declared range numbers and `scale` to each signal in `edfcore json`, so the
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
package/src/format-header.ts
CHANGED
|
@@ -58,9 +58,34 @@ function dimensionSuffix(signal: EdfHeader['signals'][number]): string {
|
|
|
58
58
|
return dimension === '' ? '' : ` ${dimension}`;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* The rate for the table, rounded when the exact value would not fit in a column.
|
|
63
|
+
*
|
|
64
|
+
* `sampleRateHz` is `samplesPerRecord / recordDurationSeconds`, and that division does not have to
|
|
65
|
+
* come out. A 0.29 s record holding 20 samples is 68.96551724137932 Hz, and interpolating it raw
|
|
66
|
+
* put seventeen digits into a nine-character column — pushing `range` off its position on that row
|
|
67
|
+
* alone, which is the alignment `formatHeader` was fixed for once already in 0.3.96, arriving by a
|
|
68
|
+
* different route. It also stated a derived quotient to the last bit of a float64, in a table whose
|
|
69
|
+
* other numbers are what the file says.
|
|
70
|
+
*
|
|
71
|
+
* `~` rather than a silently rounded number, because this module promises never to invent a value.
|
|
72
|
+
* The exact rate is on `signal.sampleRateHz`, `edfcore signals` prints it unrounded for scripts,
|
|
73
|
+
* and `samplesPerRecord` is the authoritative field either way — `cli.md` says to index by that and
|
|
74
|
+
* never by the rate.
|
|
75
|
+
*
|
|
76
|
+
* A rate whose exact spelling already fits is printed exactly, so the ordinary file is unchanged
|
|
77
|
+
* and the tilde means something when it appears. A rate too small to survive two decimal places
|
|
78
|
+
* falls back to the exact value rather than printing `~0 Hz`, which would be a claim rather than a
|
|
79
|
+
* rounding.
|
|
80
|
+
*/
|
|
61
81
|
function formatRate(signal: EdfHeader['signals'][number]): string {
|
|
82
|
+
const rate = signal.sampleRateHz;
|
|
62
83
|
// undefined is the honest answer for a zero record duration, which is legal EDF.
|
|
63
|
-
|
|
84
|
+
if (rate === undefined) return '—';
|
|
85
|
+
const exact = `${rate}`;
|
|
86
|
+
if (exact.length <= 6) return `${exact} Hz`;
|
|
87
|
+
const rounded = Number(rate.toFixed(2));
|
|
88
|
+
return rounded === 0 ? `${exact} Hz` : `~${rounded} Hz`;
|
|
64
89
|
}
|
|
65
90
|
|
|
66
91
|
/**
|
|
@@ -140,13 +165,26 @@ export function formatHeader(header: EdfHeader, options?: FormatHeaderOptions):
|
|
|
140
165
|
}
|
|
141
166
|
|
|
142
167
|
lines.push('');
|
|
168
|
+
/*
|
|
169
|
+
* Wide enough for the largest index in THIS file, never narrower than the three the heading has
|
|
170
|
+
* always used. EDF's signal-count field is four characters, so 9999 signals is a legal file and
|
|
171
|
+
* a thousand-channel one is an ordinary high-density recording — and a fixed width of three put
|
|
172
|
+
* signal 1000 one column to the right of signal 999, in the middle of the same table. Rows
|
|
173
|
+
* either side of that boundary had their last three columns in different places, which is worse
|
|
174
|
+
* than a table that is uniformly wrong: nothing about it looks like a formatting decision.
|
|
175
|
+
*
|
|
176
|
+
* A file with fewer than a thousand signals prints exactly what it printed before (0.6.24).
|
|
177
|
+
*/
|
|
178
|
+
const indexWidth = Math.max(3, `${Math.max(0, header.signals.length - 1)}`.length);
|
|
143
179
|
// Built from the SAME widths as the data rows below, not spaced by hand. The hand-spaced literal
|
|
144
180
|
// had one space too many after `label` and one after `kind`, so `kind` sat at column 27 over data
|
|
145
181
|
// at 26 and `rate` and `range` were two out — on every file, in the output whose whole purpose is
|
|
146
182
|
// being read in a terminal (fixed in 0.3.96).
|
|
147
|
-
lines.push(
|
|
183
|
+
lines.push(
|
|
184
|
+
`${'#'.padStart(indexWidth)} ${'label'.padEnd(21)}${'kind'.padEnd(12)}${'rate'.padEnd(9)} range`,
|
|
185
|
+
);
|
|
148
186
|
for (const signal of header.signals) {
|
|
149
|
-
const index = String(signal.index).padStart(
|
|
187
|
+
const index = String(signal.index).padStart(indexWidth);
|
|
150
188
|
// Control characters are replaced, not printed. A label holding a newline would otherwise
|
|
151
189
|
// render as two rows and forge a signal the file does not contain; a tab would shift every
|
|
152
190
|
// column after it. EDF pads labels with spaces and says nothing about what else may be in
|