office@biosoft-m.ru 8 (495) 729-43-14

Универсальное представление приборных сигналов

Данная информация предназначена только только для IT-специалистов по системной интеграции модулей БИОСОФТ-М. (см. Руководства пользователя к программным продуктам)


Это вечный черновик. Надеюсь предельная абстрактность никогда не материализуется ибо по определению эфемерна она и бесполезна в своей нематериальной оторванности от повседневных нужд пролетариата. Однако упражнения в абстрагировании в данных темах помогают избежать структурных ошибок из за узости локальных хаков, лишней несовместимости протоколов и терминологических рассогласованностей между разработчиками.


О представлении сигналов в каких протоколах идет речь

Это тема о высокоуровневом концептуальном представлении сигналов. Низкоуровневые пакетные, побайтные и побитные протоколы для трансфера см Category:Протоколы Unimod

Предпосылки

Программный и аппаратный протокол передачи, естественно, хранения, отображения и обработки приборных данных в софте нашей корпорации. Даная потребность продиктована потребой дня: с одной стороны, это огромное количество приборов, которые невозможно каждый раз бросаться программировать с нуля, а с другой, потребность интеграции широкого набора этих приборов в рамках одного предложения, где необходимо полученные данные не только синхронно регистрировать, отображать и хранить, но и обрабатывать.

Уровни применения

Надо разделить проблемы. От высоких уровней вниз:

  • концептуальное универсальное представление сигналов
  • полиморфные объекты (в С++)
  • хранимая информация, метаданные и взаимосвязи
  • структура в реляционной форме
  • линейный бинарный формат,
    • в т.ч. interleaved- в т.ч.
    • online incremental
Shef

1. Прежде всего универсальность и модульность реализации.

2. Возможность гибкого конфигурирования той спецификации оборудования, которая актуальна для данных мониторинговых исследований.

3. Поддержка режима "горячего" обновления списка используемых модулей мониторинга в рамках сеанса обследования.

4. Возможность автоматической индетификации модулей мониторинга.

5. Равноправность методик, реализуемых каждым из модулей мониторинга,т.е. пользователь сам определяет, какие методики обследования для него важны для работы.

6. Четкость и прозрачность протокола для идентификации специфицированной информации.

7. Наличие в протоколе сервисной информации для внутреннего потребления.

8. Простота реализации в фирменных разработках - ключи, устройства и т.д.

Абстракция

Сначала представляем себе канал и девайзы бесконечной скорости и бесконечного объема памяти. Формулируем следовательно идеальный протокол без оптимизаций. Это избавит от битов, байтов и сжатий. Решим вопросы идентификации, привязки и interleave.

Терминология

Концептуальное универсальное представление сигналов

 i Нужно только понимать что это не навязывание структуры классов какого то (или каждого) приложения.

 

Sample : anything
Record
 - Sample[n]
 - Time0
 - TimeLast
 - parent: Signal
Signal
 - Record[n]
 - parent: Multichannel
Multichannel
 - Signal[n]
 - my Source
 - parent: Session
Session
 - Multichannel[n]
 - my attributes (patient? comments? soft versions? undo data? .....)
Source
 - my Nature
 - my Device
 - status, config, etc
Nature (enum: RawAudio, Envelope, IndexSet, Eeg, EmbolMarker, UserComment, ErrorEvent, ..........)
Device
  - map Nature[n] to array of InCom[n]
  - status, config, etc (variable)
InCom : abstract class
     InComExternal extends InCom
     InComSource extends InCom
            - my Source

Тогда Device может для разных своих Nature иметь либо внешние источники (InComExternal - как сырой звук или сообщения UI) либо внутренние источники заведенные на один из Source (InComSource - Spectrum from RawAudio, EmbolMarker from Spectrum+RawAudio, ...).

Это пока представление для нас самих. Как мы это будем закладывать в ЭВМ во всех аспектах это вопросы следующих уровней и разных проекций.

Речь тут не идет ни о протоколе, ни о структуре БД, не об UI, не об инкапсуляции а о трансцедентном, способном воплотится в конечные формы ограниченные, приземленные как есть они.

  • Да, это высоко концептуально, но оправдано в рамках
    • трансцедентном, способном воплотится в конечные формы ограниченные, приземленные как есть они.

В классы это может проецироваться самыми разными способами. На практике каких то элементов не будет, какие то добавятся. Зависит от специфики приложения, аспекта (БД, UI, math, transfer...), уровня (impl, iface, ifacegp, SDK, javascript, ....) и т.п.

Главное чтобы любые представления сигналов понимали частным случаем какой концепции они являются, использовали общие термины и могли сообщаться и однозначно конвертировать информацию.

Универсальная рисовалка

(вынести отсюда в Usee!)

Мне видется 2 пути:

1) Рисовалка предоставляет какой-то callback для приложения, которое знает что это за сигнал. Приложение дает необходимые данные для этой конкретной рисовалки. Бред мы же не хотим привязываться к конкретной рисовалке. Может тут какой MultipleDispatch пройдет через объект хелпер.

2) Сэмпл в интерфесе объявляет методы итерации себя в примитивах (int, num) и/или переключатель на один из этих методов.

И я пока абсолютно не представляю что тут можно оптимизировать и как при таких уровнях абстракции, но универсальность конечно гигантская.

А кто сказал, что рисовалке давать сэмплы нужно? Я ей весь сигнал дам и пусть она сама решает, как быстрее вывести. Рисовать ли по сэмплам, или прямоугольниками, а может полилайнами для скорости.

Сэмпл - тут абстракция, означающая минимальный размер объекта. В 3D это может быть и шарик, например, а не точка

Sample : anything

— А что значит anything? В конечном итоге абстрактный painter должен нарисовать каждый семпл. Как он будет взаимодействовать с sample-ом.а если мы хотим целую кривую отрисовать? Зачем нам каждый семпл, если оптимизированно всю ее вывести хотим?

— И как ты себе это представляешь?Рисовалка ничего не знает о сигнале кроме того что он состоит из семплов.

Sample::
  GetNumAmplitude
  GetPositiveIntAmplitude
  GetBipolarIntAmplitude
  GetMainShortStr
  GetFullText
  GetContainedMultichanel
  GetSomethingElseMyOutputGeneratorCanRender
  QueryType



Оптимизированная обработка низкоуровневых массивов

В конечном итоге абстрактный painter должен нарисовать каждый семпл.

— а если мы хотим целую кривую отрисовать? Зачем нам каждый семпл, если оптимизированно всю ее вывести хотим?

— Это отличный вопрос один из главных и сложных во всей концепции этих универсальных интерфейсов [не углубляясь в офтоп Usee / Udb]

Каждый интерфейс где существенно быстродействие должен понимать не только дискретные виртуально структурированные

 Record
 Signal
 Multichannel

но их их частные формы.

Если хранилище, рендерер, сендер, паковщик, обработчик понимают например array<short> (или CAudioSliceGp который надо глобализовать) то они должны предпочитать выбор этих частных случаев над более общим с виртуальными функциями (= очень медленными)

Не забываем что сигнал это не только array<int> но и список маркеров например, выводится может не только на экран но и экспортироваться во внешние форматы, хранится может не только в памяти но и в БД разного рода целиком, частично, в офлайн, в онлайн инкрементно

от

   DrawPolyline(a, nCount)

или

   rAudioSlice.AppendSlice(rSlice)

до

   ExportToExcel(aMarkerList)

или

   UpdateDb(keyNext, rNewEvent)
Нужны конвертеры всего что угодно

Т.е. если мы хотим нарисовать список маркеров как гистограмму, нам нужно сделать ковертор "Список маркеров" -> array<int> на каком-то уровне, правильно?

И потенциально нам нужно понатыкать конверторов "все что угодно" -> "во все что угодня для отрисовки конкретным Painter-ом".

UseeSample
{
  // до сих пор не понял кто определяет интрфейс Usee или приложение
}
 
USeeRecord
{
 
  // optimized access
 
  List<rgb> GetAsRgbColorArray();
 
  List<int> GetAsIntArray();
 
  List<xxx> GetAsXxxArray();
 
  private array<UseeSample> m_aUseeSample;
}
 
USeeSignal
{
  private array<UseeRecord> m_aUseeRecord;
}
 
UseeRender
{
   RenderSample(UseeSample);
 
   RenderRecord(UseeRecord);
 
   RenderSignal(UseeSignal);
}
 
UseePainterBitmap : USeePainter
{
    OnRenderRecord(UseeRecord record)
    {
        this->DoRender(
            record.GetAsRgbColorArray());
    }
}
 
UseePainterRtfTable : USeePainter
{
    OnRenderRecord(UseeRecord record)
    {
        this->DoRender(
            record.GetAsIntArray())
    }
}


Как то так?

Нужна фабрика которая будет создавать (чего-то еще нужно (?)) конкретные реализации CUseeSample/CUseeRecord/CUseeSignal. Также она должна наверное создавать type, который должен заниматься преобразованием этих объектов в формат удобный для конкретного UseeRender. Это позволит разгрузить интрфесы Sample/Record/Signal чтобы там не было методов типа GetAsXxxForConcreteRender();

А если каждый маркер - это уже битмап? Тогда нужно будет сразу выводить, без доведения до низкоуровневого преобразования...

Идея выводить каждый объект своими способами, наиболее оптимальными в данном случае.

Каждый Render должен определить свой формат входных данных с которыми он справится, так?

Конверторы опциональны
Sample::
  GetNumAmplitude
  GetPositiveIntAmplitude
  GetBipolarIntAmplitude
  GetMainShortStr
  GetFullText
  GetContainedMultichanel
  GetSomethingElseMyOutputGeneratorCanRender

По сути это скорей не Get а Query то есть с возможностью узнать может ли данный семпл предствить себя в данном формате. Если он не может быть не int не num то все гистограммы по нему отпадают. 

Т.е. Usee определит универсальный интерфес на абсолютно все случаи жизни, которые им поддерживаются, а приложение будет выбирать, что из этого оно готово реализовать. Так?

Будет медленно

Меня кстати вчера "лечили" что такой уровень декомпозиции ни к чему хорошему не приводит. Все будет жутко медленно и нельзя столько классов лепить 

Я где то выше писал что тут не про классы речь ведем.

А ниже писал что array<short> никто не отменяет, ничто не заменяет.