На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: RaD, nsh
  
> Циклический буфер - предлагайте свои алгоритмы. Я пока в ауте
    Циклический буфер - предлагайте свои алгоритмы. Я пока в ауте
      Написал пример, ещё не тестировал...
      //Пример применения цикличного буфера для потоков записи событий и обработки.
      // !!!При замене char * на short * коррекции подлежат строки
      // !!! c memcpy(..) и c int(adr1-adr2)
      //
      #define LENBUF 64000 // длина буффера для записей( с потолка)
      #define MINOBR 4096 // минимальное количество данных для начала обработки
      //====== Переменные для потока записи =======
      static char *bufsob; //адрес физического начала буфера
      static char *curadr; //текущий адрес внутри буфера для записи
      static int n_overflow; // счётчик коллизий на нехватку места в буфере
      //====== Переменные для потока записи и обработки =======
      static char *endadr; //первый адрес за концом буфера, вообще-то потоки её не меняют
      //====== Переменные для потока обработки =======
      static char *obradr; //текущий адрес внутри буфера для обработки
      //=============================================
      //-------------- Основной поток -----------------
      //Инициализация буфера
      int Init_buf()
      {
      //выделяем место под буфер
      bufsob = new char[LENBUF];
      if(bufsob == 0) return 0;
      curadr=bufsob; // текущий адрес записи на начало буфера
      obradr=bufsob; // текущий адрес обработки на начало буфера
      endadr=bufsob+LENBUF; // первый адрес за концом буфера
      n_overflow=0; // счётчик переполнений буфера
      return LENBUF;
      }
      //------------ Подпрограмма для записывающего потока -----------
      //Заносим одну запись в буфер
      //buf - адрес где находится, то что нужно занести в буфер
      //lentowrite - количество байтов для переноса в буфер
      //возврашаем количество действительно перенесённых байтов
      int Write_buf(char *buf, int lentowrite)
      {
      int len=0,lentocur=0,lentostart=0;
      char *newadr; //расчётный адрес после операции переноса
      char *tmpobr; //для локального использования адреса обработки obradr
      if(lentowrite==0) return 0; //Уйдём сразу
      //переносим содержимое buf в буфер
      newadr=curadr+lentowrite; //ожидаемое положение
      //количество дописываемого в конец буфера
      lentocur=lentowrite; //пока думем что всё сможем
      lentostart=0;
      //перепрыгнем ли мы через конец буфера?
      if(newadr >= endadr) //перепрыгнули
      {
      //количество записываемого с позиции curadr
      lentocur=int(endadr-curadr);
      //количество записываемого с позиции bufsob
      lentostart=lentowrite-lentocur;
      newadr=bufsob+lentostart; //новый текущий адрес
      }
      //Проверим на выход за границу буфера
      if(newadr >= endadr) newadr -=LENBUF; //кольцуем
      //проверим не перегоним ли мы obradr после записи
      //оперировать с obradr на чтение можем всегда без проблем
      tmpobr=obradr;
      //сначала проверим по lentocur
      if( (curadr == tmpobr) ) //перепрыгнули
      {
      lentocur=int(tmpobr-curadr)-1; //уменьшим до возможного
      lentostart=0; //что делать, придётся отбросить.
      newadr=curadr+lentocur; //что делать, придётся.
      //Проверим на выход за границу буфера, хотя здесь это излишне
      if(newadr >=endadr)newadr -=LENBUF; //кольцуем
      n_overflow++; //отметим переполнение буфера
      }
      //теперь проверим по lentostart
      if(lentostart && (newadr >= tmpobr) ) //перепрыгнули
      {
      lentostart=int(tmpobr-bufsob)-1; //уменьшим до возможного
      newadr=bufsob+lentostart; //что делать, придётся.
      //Проверим на выход за границу буфера, хотя здесь это излишне
      if(newadr >=endadr)newadr -=LENBUF; //кольцуем
      n_overflow++; //отметим переполнение буфера
      }
      //запишем сколько можно в буфер
      if(lentocur)memcpy(curadr,buf,lentocur);
      if(lentostart)memcpy(bufsob,&buf[lentocur],lentostart);//Остаток
      mend:
      curadr = newadr; //смещаем текущий указатель на новое место
      return (lentostart+lentocur);
      }
      // ------------ Поток обработки -----------
      void Execute()
      {
      int len,lenkdr,i;
      char *newadr; //расчётное положение указателя обработки
      char *tmpcur; //для локального использования запомним адрес записи здесь
      //Переменные для обработки
      char *astart; // действительный адрес в буфере найденного начала кадра
      char *aend; // действительный адрес в буфере найденного конца кадра
      //Эти переменные могут показаться излишними, но с ними понятнее
      int id_start; //признак найденного начала кадра
      int id_end; //признак найденного конца кадра
      //Временные переменные для Check_Kadr(...)
      char *tmpstart; // временная переменная - адрес в буфере найденного начала кадра
      char *tmpend; // временная переменная - адрес в буфере найденного конца кадра
      id_start=0; id_end=0; //Изначально кадра для обработки нет
      tmpstart=0; tmpend=0; //временные указатели на кадр
      //Залазим в обработочный цикл
      while(!Terminate) //выходим если потребовал основной поток
      {
      //curadr можем использовать на чтение без проблем
      tmpcur=curadr;
      if(obradr==tmpcur)continue; //Данные ещё не поступили
      // Посчитаем сколько готово данных для обработки
      //Полагаем что obradr в буфере находится перед tmpcur
      len=int(tmpcur-obradr);
      if(len =endadr) newadr -=LENBUF; //новый адрес обработки
      obradr=newadr; //Смело можем записать новый адрес
      }
      continue; //Продолжим ждать данных
      }

      if(tmpstart ) //Нашли начало кадра
      {
      //Что делать если начало было уже найдено ранее и не обработано?
      //Сейчас просто пропустим прежнее начало без обработки
      if(id_start)id_start--; //количество необработанных начал кадра
      //Запомним адрес начала кадра
      astart=tmpstart;
      id_start++; //количество необработанных начал кадра
      //Теперь освободим лишний участок буфера до кадра
      newadr=tmpstart;
      if(newadr >=endadr) newadr -=LENBUF; //новый адрес обработки
      obradr=newadr; //Смело можем записать новый адрес
      }
      if(tmpend) //Нашли конец кадра
      {
      //Что делать если начало было уже найдено ранее и не обработано?
      //Сейчас просто пропустим прежний конец без обработки
      if(id_end)id_end--; //количество необработанных концов кадра
      //Запомним адрес конца кадра
      aend=tmpend;
      id_end++; //количество необработанных концов кадра
      }
      if( !id_start !! !id_end) //Кадр не сформирован
      {
      //Проверим упёрся ли поток записи в начало обработки
      //Если упёрся, а мы не нашли концы кадра, то придётся сваливать без обработки
      newadr=tmpcur+1;
      if(newadr >=endadr) newadr -=LENBUF;
      if(obradr==newadr) //упёрся в нас поток записи
      {
      id_start=0; id_end=0; // Непрерывность нарушена
      tmpend=0; tmpstart=0; // поиск будет продолжен с позиции obradr
      //Смести указатель в позицию tmpcur ( это curadr потока записи)
      obradr=tmpcur;
      }
      continue; //ждем новых данных
      }
      //Если кадр выделен можем приступить к его обработке
      //.... //Обрабатываем кадр и формируем его характеристику
      //И далее по алгоритму, можно в другом потоке
      //..
      // освободим обработанный участок буфера
      id_start=0; id_end=0;
      tmpend=0; tmpstart=0; // поиск будет продолжен с позиции obradr
      //Смести указатель в позицию tmpcur
      obradr=tmpcur;
      }

      //заканчиваем поток обработки
      return ;
      }
        Потестировал и есть замечание...
        Провёл тестирование с использованием трёх потоков: основной, запись, обработка.
        Размер записи делался с использованием random(2048).
        Необходимо изменить конец подпрограммы Write_buf(..). Так как возможна ситуация с
        lenstart =endadr)newadr -=LENBUF; //кольцуем
        if(newadr 0)
        {
        memcpy(curadr,buf,lentocur);
        if(lentostart>0)memcpy(bufsob,&buf[lentocur],lentostart);//Остаток
        }
        mend:
        curadr = newadr; //смещаем текущий указатель на новое место
        return (lentostart+lentocur); //может быть и меньше нуля
        }
        //++++++++++++++++++++++++++++++++
        При тестировании была устойчивая работа при приостановке любого из потоков. После пауз всё продолжало работать.
          Причесал запись...
          После приведения в порядок получилось следующее:
          //------------ Подпрограмма для записывающего потока -----------
          //Заносим одну запись в буфер
          //buf - адрес где находится, то что нужно занести в буфер
          //lentowrite - количество байтов для переноса в буфер
          //возврашаем количество действительно перенесённых байтов
          int __fastcall TMyThread::Write_buf(char *buf, int lentowrite)
          {
          int len=0,lentocur=0,lentostart=0;
          char *newadr; //расчётный адрес после операции переноса
          char *tmpobr; //для локального использования адреса обработки obradr
          if(lentowrite==0)return 0; //Уйдём сразу
          //оперировать с obradr на чтение можем всегда без проблем
          tmpobr=obradr;
          //Посмотрим сколько есть свободного места в буфере
          //между указателем на запись и обработкой должно быть
          // не меньше одной ячейки
          len=int(tmpobr-curadr)-1;
          if(len len){ lentowrite=len; n_overflow++ ; }
          //переносим указатель записи
          newadr=curadr+lentowrite; //ожидаемое положение
          //количество дописываемого в конец буфера
          lentocur=lentowrite; //пока думем что всё сможем
          lentostart=0;
          //перепрыгнем ли мы через конец буфера?
          if(newadr >=endadr) //перепрыгнули
          {
          //количество записываемого с позиции curadr
          lentocur=int(endadr-curadr);
          //количество записываемого с позиции bufsob
          lentostart=lentowrite-lentocur;
          }
          //Проверим на выход за границу буфера
          if(newadr >=endadr)newadr -=LENBUF; //кольцуем
          //Делаем перенос
          if(lentocur)memcpy(curadr,buf,lentocur);
          if(lentostart)memcpy(bufsob,&buf[lentocur],lentostart);//Остаток
          mend:
          curadr = newadr; //смещаем текущий указатель на новое место
          return (lentostart+lentocur); //количество перенесённого
          }
            re: Причесал запись...
            Извините, что вмешиваюсь,
            Я внимательно прочитал ваш разговор,
            но не понял одного, ЧТО именно Вы хотите создать!
            Если дикторозависимую программу распознавания, то
            не понятно, зачем её делать, если она уже есть
            и благополучно продаётся во всём мире.
            её автор - Американская компания Dragon Dictate.
            Весь остальной софт это её производные от проданных ими компонент другим фирмам в том числе и IBM!
            Мало того эти компоненты свободно лежат у них на сервере пользуйтесь, кто хочет.
            Я это делал год назад.
            Русский движок-их компоненты прекрасно работают с
            русской речью(дикторозависимо).
            Они напрополую используют Фурье.
            С моей точки зрения вы идете по их стопам, только не учитываете, что они этот путь прошли за 10 лет со штатом в 200 чел. с хорошей зарплатой.
            Я случайно присутствовал на переговорах с DD о разработке Русской версии, где они категорически отказались(ни за какие деньги!!!)
            Причина:
            1.Фурье методом невозможно распознать окончания Русских слов.
            2.В Русском языке каждому слову соответствует в среднем 20-30 словоформ.
            (в английском-2-3)
            3. По этой причине происходит соответствующее увеличение словарной базы,а 200 000 слов пока потолок.
            Это, что касается Фурье, а значит-фонемы, а значит дикторозависимость.
            Этот путь в принципе не верный, хотя может пригодиться для, например голосового пароля(идентификации).
            Я над этим вопросом работаю уже 7 лет.
            Единственнвй путь чёткого распознавания любого голоса - нахождение и идентификация
            "особых точек".
            Хотите возразить?
            Безполезно - доказательство и почти решение как всегда на поверхности...
            Пример:
            к Вам сзади подошёл кто-то и прошептал Что-то...
            и Вы его поняли, мало того Вы его узнали!!!
            Как Вы это сделали?
            Много ли фонем в шёпоте?
            В шёпоте от несущей голоса осталась львиная доля
            особых точек! И совсем мало фонем! зато почти вся полезная информяция для распознавания - осталась.
            (пример конечно не очень удачныё т.к.
            звук "Г" в шёпоте = "К" ,но этот пример только для понимания)
            Осталось всего лишь выделить особые точки,
            наделить их соответствуюшими именами и коэффициентами,
            аппроксимировать линейой функцией,
            и определить границы существования.
            Чем больше особых точек, тем выше идентификация.
            и не надо искать начало слова, конец и т.д.
            Хотите пример особой точки - пожалуйста:
            Произнесите в микрофон слово "ПОДЪЕМ"..
            Посмотрите на его амплитудную характеристику...
            После звука "Д" идёт длиннющая пауза,
            а в слове "ОТТОЧИТЬ" эта пауза в 5-6 раз длиннее!
            Имеем особую точку 1 с коэффициентом длины.
            определяем линейную функцию, как матрицу заполненную нулями.
            Резюме.
            1.Для уверенного распознавания достаточно 40-70 особых точек.
            2.Я смог обнаружить таких-87.
            3.Всего их может быть ~1000 , а может и бесконечность, например смешивание речи с тиканием часов. База особ. точек часов будет отличаться от базы речи.
            4. Можно построить базу О.Т. для разных акцентов, людей и т. д.
            5. На сегодняшний день у меня в базе всего 6 О.Т.
            Это уже ~600 слов в словаре.
            6. если подключить 7-ю то база увеличится в 2 раза.
            Конечно готового коммерческого продукта пока нет,
            но годика через 2 я подключу ещё 15-20 точек.
            С уважением Влад.
              Поделился бы некоторыми наработками, теорией и т.д.
                Влад, пока здесь выбирается подход к решению.
                Решение же, в моём понимании, не имеет однозначного ответа. И поэтому здесь формируется частный подход. Главным принципом которого, является независимость от титанов. Как и при решении любой научной задачи, сначала необходимо сделать инструментарий для анализа поступающей экспериментальной информации. Затем построение зависимостей. Затем определение инвариантов. ... То есть, обычная работа экспериментатора. Кто удачнее представит перед своим взором обработанный материал, тому легче будет его переварить в голове. (Пример: таблица Менделеева).
                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                0 пользователей:


                Рейтинг@Mail.ru
                [ Script Execution time: 0,0990 ]   [ 17 queries used ]   [ Generated: 7.12.19, 21:55 GMT ]