feat: the export writes an MDF 3.30 file, so a window loads in ScryLab
A third format beside `.npy` and `.csv`, written by hand in `src/export.cpp` -- MF4 is HDF5 and would mean a library, MF3 is a handful of fixed blocks. The layout is the asammdf 8.8.27 reader's own field list, byte-diffed against a known-good 3.30 file it wrote; the shape is the one ScryLab's data-source contract asks for: one channel group, record-interleaved, the master as the x axis, and the unit in the channel's conversion block. So in MDF the master is `abs_seconds`, named `time` -- the clock that is the same in every display mode -- and the plotted axis goes out as an ordinary channel, `time_relative`. `ExportTable::Column` gained the CONFIG's unit, which only this writer spells out; the `.npy`/`.csv` bytes are unchanged, and `write_export()` now picks the writer for both the dialog and the probe.
This commit is contained in:
1 parent
761615c2fe
commit
908286ee89
10 files changed
+505
-28
No files matched your search
@@ -21,6 +21,11 @@ namespace udpscope {
|
||||
struct ExportTable {
|
||||
struct Column {
|
||||
std::string name; ///< the legend name, sanitised for a column label
|
||||
/// The signal's unit exactly as the CONFIG carried it, the empty string when it
|
||||
/// carried none. The `.npy`/`.csv` writers do not spell it out (their readers get the
|
||||
/// names and the numbers); MDF does, because the unit *is* part of what a channel is
|
||||
/// there, and it is the only thing ScryLab reads a signal's unit from.
|
||||
std::string unit;
|
||||
std::vector<f32> values; ///< `rows()` long, the ring's own `f32`
|
||||
};
|
||||
|
||||
@@ -71,4 +76,27 @@ bool write_npy(const std::string& path, const ExportTable& table, std::string& e
|
||||
/// enough digits to round-trip each column's own type and no more.
|
||||
bool write_csv(const std::string& path, const ExportTable& table, std::string& error);
|
||||
|
||||
/// Writes the same table as **MDF 3.30** (`.mf3`/`.mdf`), byte for byte by hand -- there is no
|
||||
/// writer library here and MF4 (HDF5) is the one format this app will not link.
|
||||
///
|
||||
/// One channel group, all channels record-interleaved, master first, which is the shape the
|
||||
/// [ScryLab data sources](https://docs.scrylab.de/docs/data-sources/) contract asks for: *every
|
||||
/// data channel becomes a signal* (the CNBLOCK's `short_name`), *the master channel of each
|
||||
/// group is the x axis* (our master is `abs_seconds`, named `time`), and *the unit is taken from
|
||||
/// the channel metadata* (MDF 3 keeps it in the channel's conversion block, the CCBLOCK). A
|
||||
/// second occurrence of a name is dropped by that reader, so the labels are de-duplicated and cut
|
||||
/// to the 31 bytes a CNBLOCK's name field holds.
|
||||
///
|
||||
/// The master is the **absolute** clock and the axis the plot showed is an ordinary channel,
|
||||
/// `time_relative`: the relative column is `0` at a different sample in every mode, so a master
|
||||
/// off it would put two exports from different modes on two timelines, while `abs_seconds` is the
|
||||
/// number the stream itself stamped the samples with. Both carry the unit `s`.
|
||||
bool write_mdf(const std::string& path, const ExportTable& table, std::string& error);
|
||||
|
||||
/// Writes `table` with the writer **`path`'s extension** names: `.csv` -> `write_csv`,
|
||||
/// `.mf3`/`.mdf` -> `write_mdf`, anything else -> `write_npy` (the default, as the save dialog's
|
||||
/// default filter is). The export dialog and the self-check's export probe both come through
|
||||
/// here, so the two cannot offer different formats.
|
||||
bool write_export(const std::string& path, const ExportTable& table, std::string& error);
|
||||
|
||||
} // namespace udpscope
|
||||
Reference in new issue
Block a user