Page 1 of 212»

31st
Авг

Получить длительномть трека. Bass.dll

Код:

function QBass_GetTime(const Channel: DWORD): DWORD; stdcall;
var
  pPos: Cardinal;
  AllTime: Cardinal;
begin
  result := 0;
  pPos := BASS_ChannelGetLength(Channel, BASS_POS_BYTE);
  if (pPos > 0) then
  begin
   Alltime := Trunc(BASS_ChannelBytes2Seconds(Channel, pPos));
   Result := Alltime;
  end;
end;

вот так получай длину трека

Код:

var
  mch: dword;
  lng: dword;
begin
  mch := BASS_StreamCreateFile(false, pointer(fname), 0, 0, 0 );
try
  lng := qbass_gettime(mch);
  // тут преобразовывай время в строку
finally
  bass_streamfree(mch);
  mch := 0;
end;
end;

Тема на форуме.

30th
Авг

→ Выбираем логотип журнала ПРОграммист ←

Прикрепляем к сообщению свои варианты. Имейте совесть, не грузите людей простынёй из 50 вариантов :)
1 человек – 1 пост / 1 лого – 1 файл.
В пост влазит 5 файлов, соответственно каждый может предложить 5 вариантов.

Варианты, естественно, не окончательные, будут дорабатываться до человеческого состояния. Потом прилепим голосование (возможно в 2 тура)

Обсуждение здесь

Перейти к теме на форуме.

30th

RxTrayIcon

Есть форма. На ней RxTrayIcon. В событии формы FormCloseQuery прописано:

Form1.Hide;
CanClose := False;

Тоесть при нажатии на крестик, приложение не закрывается а сворачивается в трей. Потом по щелчку на иконку в трее приложение восстанавливается. Но если снова нажать на крестик никаких событий не происходит. Также после закрытия приложения полностью, в трее остается иконка до тех пор пока на нее не навести курсор, после чего она исчезает. Кк можно решить эти проблемы?

Вот схема, которая работает.

Код:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, RXShell, StdCtrls;

type
  TForm1 = class(TForm)
    Tray1: TRxTrayIcon;
    Button1: TButton;
    procedure Tray1Click(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);  //OnClick TRxTrayIcon в Object Inspector
    procedure FormCreate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure Button1Click(Sender: TObject);
  private
    FullClose : Boolean;
    procedure ApplicationRestore(Sender : TObject);
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Tray1Click(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then begin
    Application.Restore;
    Application.BringToFront;
    Show;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnRestore := ApplicationRestore;
end;

procedure TForm1.ApplicationRestore(Sender: TObject);
begin
  ShowWindow(Application.Handle, SW_RESTORE);
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if FullClose then CanClose := True
  else begin
    CanClose := False;
    ShowWindow(Application.Handle, SW_HIDE);
    Hide;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject); //закрыть приложение
begin
  FullClose := True;
  Close;
end;

end.

Перейдите на форум за доолнительной помощью. В теме много полезного и интересного.

30th

Конвертирование utf-8 в windows-1251

Код:

string Utf8_to_cp1251(const char *str)
{
	string res;
	int result_u, result_c;

	result_u = MultiByteToWideChar(CP_UTF8,
		0,
		str,
		-1,
		0,
		0);

	if (!result_u)
		return 0;

	wchar_t *ures = new wchar_t[result_u];

	if(!MultiByteToWideChar(CP_UTF8,
		0,
		str,
		-1,
		ures,
		result_u))
	{
		delete[] ures;
		return 0;
	}

	result_c = WideCharToMultiByte(
		1251,
		0,
		ures,
		-1,
		0,
		0,
		0, 0);

	if(!result_c)
	{
		delete [] ures;
		return 0;
	}

	char *cres = new char[result_c];

	if(!WideCharToMultiByte(
		1251,
		0,
		ures,
		-1,
		cres,
		result_c,
		0, 0))
	{
		delete[] cres;
		return 0;
	}
	delete[] ures;
	res.append(cres);
	delete[] cres;
	return res;
}

Тема на форуме.

27th
Авг

Искусство изменеия GTA

аватар

Здравствуйте, любители гейминга. В данной статье, я хочу показать, как делаются плагины для всем известной GTA. Начнем мы самого простого – это программирование плагинов на Delphi для Grand theft Auto ViceCity. А поняв принцип их работы, никакого труда не составит написать плагин и для других серий GTA…

Виталий Иванов
by VintProg vintprog@gmail.com

Пишем простой плагин для GTA – VC*

Итак, Для работы нам понадобится следующее:

  1. IDE среда Delphi [1]
  2. знание языка
  3. утилита ArtMoney** [2]

И немного теории, что же такое плагины. Плагины – это те же динамические подключаемые библиотеки DLL. Однако часто бывает, что им изменяют расширение.

Возможно, вы спросите: «…как же это работает все?», А работает оно следующим образом… При запуске <gta-sa.exe> загружаются комплектные библиотеки от разработчиков. В одной из этихDLL, в частности – vorbisFile.dll имеется функция загрузки библиотек *.asi, И пожелавшие остаться неизвестными, программисты написали <cleo.asi> и набили ее весьма и весьма полезными функциями, такими как: новые опкоды, загрузка плагинов *.cleo и.т.п. Когда загрузилась библиотека <cleo.asi>, ее код выполняет нужные функции в памяти игры.

* Комментарий автора.
Вы наверняка встречали Cleo на GTA-SA,и видели, что там существует такая библиотека cleo.asi, Так вот она и загружает из папки Cleo – скрипты и сами плагины .cleo.

Именно благодаря этому и появляются новые возможности в игре. А что касается GTA Vice City, то в ней тот же процесс, только библиотеки *.asi загружаются из библиотеки <Mss32.dll>. Отсюда понятно, что для того чтобы писать плагины – необходимо хорошо уметь работать с памятью игры и знать что за значения находятся в игровой памяти в определенном адресе.

** Комментарий редакции.
ArtMoney – программа, предназначенная для редактирования параметров в кмпьютерных играх, для получения бесконечных денег, жизней, патронов и т.п. Она умеет сканировать память или файлы игры для поиска каких-то определенных значений (деньги, ресурсы). Официальный сайт www.artmoney.ru

рисунок

Приступим… Для начала запустим Borland Delphi, после чего кликаем на «File -> New -> other… » и перед нами откроется вот такое окно (см. рисунок 2):

рисунок 2

Рис. 2. Выбор DLL Wizard

Далее выделяем DLL Wizard и жмем OK. Сразу возьмем и сохраним наш проект «File->Save Project As» и под именем ShowMessage, чтобы получилось как показано на рисунке 3:


рисунок 3

Рис. 3. Заготовка плагина

Также можно удалить дерективу {$R *.res} , потому-что для данного плагина мы не будем использовать ресурсы. Из дополнительных модулей оставим лишь – Windows, а остальные удалим. Теперь напишем следующий код:

код:

library ShowMessage;

uses
    Windows;

var HWND : THandle;
begin
     // Получить хендл окна GTA: Vice City
     HWND := FindWindow(nil,’GTA: Vice City’);
     if HWND <> 0 then // Проверка если окно GTA: Vice City
         // существует, то тогда выполнить MessageBox
         MessageBoxA(HWND,’Плагин загружен’,'Сообщение’,0)
end.

И скомпилируем его. Прокомментирую работу данного кода… Когда библиотека загружается, между Begin end начинает выполнятся код, Тут сразу появляется окошко с сообщением. Чтобы это заработало, переименуйте расширение *.DLL на *.ASI или воспользуйтесь директивой {$E.ASI}. После чего, скопируйте библиотеку в каталог GTA и запустите игру GTA-VC.exe, Далее мы увидим окошко, когда загрузится <mss32.dll>. Поздравляю, вы написали свой первый плагин для GTA***!

Пишем простой плагин-трейнер для GTA – VC

Настала пора сделать что-то полезное. Итак, сперва подумаем, что нам еще нужно? А нужно нам сделать плагин-трейнер. Для чего он предназначен? К примеру, мы можем сделать так, чтобы при нажатии определенной кнопки в игре – появлялось окно, в котором можно прибавить деньги игроку. Для этого, запускаем Gta-VC, сворачиваем ее и запускаем ArtMoney. В этой утилите выбираем «Искать -> Объект -> Процесс» и в выпадающем списке, где написано «Выбери процесс», выберем нашу GTA Vice City (см. рисунок 4). Теперь зайдем в GTA-VC и соберем небольшое количество денежных средств (к примеру, как я набрал $18). Судя по представлению «денег» в игре, видно, что они целого числа и можно набрать их в игре большое количество. Отсюда, мы уже знаем тип представления данных «денег».

Это 4-байтные целые числа, которые нам и нужно отыскать (см. рисунок 5).

рисунок 4

Рис. 4. Выбор GTA-VC в ArtMoney

Обратите внимание! Вам необходимо повторить те же действия, как показано на рисунке, только у вас будет свое число. По завершению поиска у вас появится длиннющий список адресов (см. рисунок 6). Но не переживайте по этому поводу. Ведь адрес «денег» мы будем искать более легким методом, На то она и ArtMoney. Следующий шаг будет таков: снова заходим в GTA и либо тратим, либо добавляем деньги к игроку Tommy, запоминаем измененное количество «денег» и сворачиваем GTA. Вписываем новое значение (см. рисунок 7):

*** Комментарий автора.
Если что то не получается то пример расположен в каталоге “Examples\Plugin1”.


рисунок 5

Рис. 5. Поиск значений по заданному типу данных

рисунок 6

Рис. 6. Выборка адресов в ArtMoney


рисунок 7

Рис. 7. Повторный поиск значений по заданному типу данных

Теперь нажимаем «отсеять». Как видите, длина списка адресов значительно уменьшится. И так продолжаем до тех пор, пока не останется один адрес. Если-же все равно остается насколько адресов, то меняем в них значения и проверяем изменилось-ли количество «денег» в GTA (см. рисунок 8). Если все нормально, то нормально. Однако, еще осталось сделать одну проверку на указатель. ArtMoney не закрываем, так все и оставляем. Вырубаем GTA-VC и заново запускаем GTA-VC. В ArtMoney, в выпадающем списке, где написано «Выбери процесс», заново выбираем GTA и повторим операции по изменению значений по адресу местонахождения «денег». Если все работает нормально, то записываем этот адрес в текстовой блокнот и вырубаем GTAVC и выключаем ArtMoney. Теперь он нам не понадобится.

Итак, первый шаг сделан. Мы нашли адрес «денег» и остается лишь написать плагин.

Распишем особенность работы плагина, то есть то – как он будет работать: так, при нажатии кнопки <M> добавляется 1000 долларов, а значит нам нужен обработчик нажатия кнопки. Воспользуемся таймером. Теперь, точно так же как и в первом примере, созадим новый проект DLL и назовем его «MoneyAdds». И напишем следующий код:

**** Комментарий автора.
Хочу напомнить, что не на всех версиях GTA-VC могут быть одинаковые адреса. Так что имейте это ввиду, при написании плагинов.

код:

library MoneyAdds;

{ GTA-VC 1.1 Плагин для добовления денег }

uses Windows;

type // определяем свой тип (указатель целых чисел)
     P_Integer = ^Integer;
var
     GTA_VC_Handle : THandle;
     CurrentMoney : Integer;
     keyUp : boolean;

const // тут твой найденный адрес «денег»
     Address_Money = $0094ADD0;

{$E .asi}

//—- Эта процедура будет вызываться таймером —
procedure Timer_begin;
begin
     // Нажатие и отпуск «M»
     if not GetKeyState($4D) < 0 then keyUp := true;
     if (GetKeyState($4D) < 0) and (keyUp = true) then
     begin
         // Читаем деньги из GTA-VC и присваиваем в CurrentMoney
         CurrentMoney := P_Integer(Address_Money)^;
         // Записываем 1000 + текущие деньги
         P_Integer(Address_Money)^ := CurrentMoney + 1000;
         keyUp := false;
     end
end;

//———————————————————–
begin
     GTA_VC_Handle := FindWindow(nil,’GTA: Vice City’);
     if GTA_VC_Handle <> 0 then
     begin
         SetTimer(GTA_VC_Handle,0,25,@Timer_begin);
     end;
end.

Исходный код этого плагина находится в «Examples\Trainer1» [3]. Вот мы и реализовали плагин-трейнер добавления «денег» по нажатию клавиши «M», Только скажу – не выгодно на каждый плагин делать один таймер, Поэтому имейте ввиду, что таймер нагружает процессор. Для решений данной проблемы можно воспользоваться функциями DirectX для обработки нажатий клавиатуры.

Пишем свой собственный менеджер-загрузчик плагинов

Вы наверняка заметили одну вещь: когда создаешь новый плагин, его приходиться бросать рядом с GTA-VC.exe, А представьте себе, если таких плагинов будет больше десятка? Это не наш метод, поэтому мы напишем свой загрузчик плагинов из отдельно созданного каталога под наши плагины, скажем <bin>. И пускай там будет их хоть 1000!

Итак, запускаем среду Delphi и по аналогии создадим проект DLL-ки. Внутри напишем следующий код:

код:

library LoaderVc;

{ Даная библиотека нужна для загрузки плагинов в GTA-VC }

{$E .ASI}

uses SysUtils, Windows;

var
     SearchRec : TSearchRec;
     filename : pAnsiChar;
const
     dir_bin = ‘Bin\*.bin’;
     dir_dll = ‘Bin\*.dll’;

//— Процедура отыскивает все плагины из папки Bin и
// подгружает их —
procedure Load_libs(FilesName : string);
begin
     if FindFirst(FilesName, faAnyFile, SearchRec) = 0 then
     repeat
         filename := pAnsiChar(‘Bin\’ + SearchRec.name);
         LoadLibrary(filename);
     until FindNext(SearchRec) <> 0;
end;

//————————————————————
begin
     Load_libs(dir_dll);
     Load_libs(dir_bin);
end.

Исходный код этого менеджера-загрузчика находится в «Examples\Loader_VC» [3].

Заключение

Вот теперь готов загрузчик плагинов bin и dll, Теперь достаточно бросить его в корневую папку GTA, создать там каталог <BIN> со всеми нашими плагинами, запустить игру и полюбоваться результатом наших трудов.

Рассматриваемые в данной статье исходники плагина добавления «денег», плагина-трейнера и менеджера-загрузчика полностью приведены в виде ресурсов в теме «Журнал клуба программистов. Пятый выпуск» или непосредственно в архиве с журналом.

Продолжение смотрите в следующем выпуске нашего журнала…

Ресурсы

Статья из пятого выпуска журнала «ПРОграммист».
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.

Обсудить на форуме – Искусство изменеия GTA

26th
Авг

Энкодер датчика pdf на плис. Часть 2

аватар

Итак, сегодня мы с вами продолжим наш материал по промышленной автоматизации, рассмотрим реализацию алгоритма энкодера на ПЛИС, особенности прошивки модулей Faswell UNIOxx-5 и создадим тестовую утилиту визуализации состояния шифратора приращений.

Продолжение. Начало цикла смотрите в четвертом выпуске журнала…

Сергей Бадло
by raxp http://raxp.radioliga.com

Согласно требований из прошлого материала [1], приведем реализацию алгоритма энкодера на ПЛИС в среде Xilinx Foundation 3.1i [2] (см. рисунки 2…8).

Каждая микросхема FPGA обрабатывает сигналы от двух датчиков. По каждому четвертому сигналу чтения READ и нулевому адресу (битовая последовательность А0…А2) передаются: младшие 8- бит 11-ти разрядной последовательности, содержащей информацию о текущем количес- тве импульсов поступивших с канала А (угловом положении). По первому адресу (А0…А2) переда- ются (с младшего по старший бит DO0…DO7): старшие 3- бита 11-ти разрядной информации о текущем количес- тве импульсов поступивших с канала А, признак отказа канала А (в течении длитель- ности стробирую- щего импульса (одного оборота), признак отказа канала В (в течении длитель ности стробирую- щего импульса (одного оборота)), признак направления вращения (определяется с началом стробирующего импульса по приходу сигналов с канала А и В (в течении одного оборота)), признак отказа канала строба О. По второму и третьему адресу (А0…А2) передаются (с младшего по старший бит DO0…DO7) 16- бит информации о количестве оборотов. По четвертому и пятому адресу (А0…А2) передаются (с младшего по старший бит DO0…DO7) 16- бит информации о количестве ТИ за длительность строба (относительной* скорости).

рисунок 1

Рис. 1. Тестируемый пациент


рисунок 2

Рис. 2. Общая схема энкодера (дешифратор адреса, формирователь кода схемы, генератор ТИ, 2 канала энкодера, 16 каналов дискретного ввода-вывода)


рисунок 3

Рис. 3. Схема одного канала энкодера (антидребезг, задатчик идентификатора схемы, реверсивный счетчик импульсов, узел формирования выходного пакета данных)

Каждая из схем энкодера (алгоритм) осуществляет:

  • измерение относительного углового положения датчика (по количеству импульсов поступивших с канала A);
  • индикацию в соответствующем бите признака наличия импульсов (исправность A, B, Q);
  • подсчет числа оборотов (количества импульсов строба), максимальное ограничено величиной 215, далее осуществляется сброс, и счет начинается заново;
  • измерение относительной скорости*, т.е. подсчета количества ТИ, поступивших за длительность строба (погрешность ограничена длительностью ТИ и нестабильностью тактового генератора).


рисунок 4

Рис. 4. Модуль задержки на 8 тактов встроенного генератора

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

* Комментарий автора. Номинальная (фактическая) скорость определяется программным методом путем вычисления:

V=4 * 2048 * Nти * Tти; (1)

где: 4 – коэффициент, учитывающий соотношение длительности строба и длительности канальных (информационных импульсов); 2048 – максимальное количество импульсов по любому из каналов; V – фактическая скорость, об/cек; Nти – количество ТИ за строб; Tти – период ТИ, поступающих с внешнего генератора (равен 20 нс), сек.


рисунок 5

Рис. 5. Схема определения направлени вращения ротора датчика PDF


рисунок 6



рисунок 6

Рис. 6. Схемы нарезки сигналов A/B


рисунок 7

Рис. 7. Схема регулирования (СР) ширины ЗИ


рисунок 8

Рис. 8. Внутренняя схема узла адресации СР

рисунок 9

Рис. 9. Реализация RS-триггера

Запустим наш проект на компиляцию. После проверки схемы, среда создаст битовый файл прошивки (файлы bitstream фирмы XILINX), который нужно прошить в соответствующую матрицу FPGA. Как это сделать?

Программирование платы UNIOхх-5

Обычно, для загрузки конфигурационной информации в ПЛИС используется JTAG интерфейс [3]. При этом последовательность действий следующая. Откройте приложение «JTAG Programmer» пакета Xilinx Foundation Series 3.1i. В меню «Edit» выберите пункт «Add Device», после чего появиться вспомогательное окно, в котором необходимо отыскать наш файл прошивки и открыть его. В меню «Operations» выберите пункт «Program». В появившемся окне нажмите кнопку «OK». После удачной загрузки, должна появиться фраза «Programming completed successfully». На этом программирование завершено (см. рисунок 10):


рисунок 10

Рис. 10. Загрузка прошивки через JTAG

Однако этот способ не лишен недостатков: требуется наличие JTAG программатора практически все время «под рукой».

Второй способ, получивший название ISP (In System Programming), более удобен, так как не требует извлечения микросхемы конфигурационного ПЗУ (или самой ПЛИС) из платы или наличия дополнительного разъема на плате под ПЛИС. Программирование каждой матрицы FPGA1…FPGA4 модуля UNIOxx-5 осуществляется с помощью программ: <isp.exe> (загрузка схемы с записью в EEPROM), <isl.exe> (загрузка схемы без записи в EEPROM). Программы позволяют осуществить загрузку файлов схем *.bit матриц FPGA. Рассмотрим на примере…

Для записи схемы и загрузки в модуль необходимо запустить программу <isp.exe> с указанием Базового Адреса (Hex) модуля и кодов схем матриц FPGA, например (см. рисунок 11):

Результат

Рис. 11. Результат


рисунок 11

Рис. 11. Окно командной строки. Запуск утилиты ISP

Питание и установка

Модуль с прошивкой энкодера устанавливается в слот (ISA) промышленного компьютера и запитан от напряжения ±5В. При этом требуется обеспечить стабильность питающего напряжения с пульсациями не более 200 мВ. Выходной сигнал – однополярное напряжение (цифровая последовательность) с током нагрузки до 10 мА. Максимальная длина шлейфа, соединяющая выход модуля энкодера (платы UNIOxx-5) к входному разъему до 1.5 м. Проверка прошитой платы UNIOxx-5 производится на рабочем месте следующим образом. Земли шасси, платы UNIOxx-5, осциллографа, генератора импульсов и генератора сигналов высокочастотного должны быть объединены (заземлены) в одной точке проводником минимальной длины сечением не менее 2 мм2 (см. рисунок 12):


рисунок 12

Рис. 12. Схема проверки платы UNIOxx-5 с прошивкой энкодера

Плата UNIOxx-5 при выключенном питании шасси вставляется в ISA слот. С помощью соединительного шлейфа присоединяют выход датчиков с соответствующими входами модулей гальванической развязки или модулей связи, сигнал с которых подан на вход платы UNIOxx-5. Далее производится включение промышленного шасси и загрузка обслуживающей прошивки. Осциллографом контролируют наличие напряжения питания (+5 В) на плате модуля UNIOxx-5. С помощью осциллографа производится контроль ТИ с тактового генератора платы. Включив генератор импульсов с заранее выставленными выходными уровнями сигналов, подают импульсы по входу строба для каждой из матрицы модуля (поочередно), контролируя одновременно с помощью программы обслуживания (или осциллографом) наличие признака строба в последовательности (бит DO7 при втором адресе А0…А2).

Кроме того, тестирование прошивки энкодера желательно провести в условиях, приближенных к «реальным». Для этого необходимо, подключить шифратор приращений через наш модуль связи, используя несколько десятков метров кабеля UTP 5-й категории обмотанного вокруг работающего частотного привода под нагрузкой. Для визуализации положения ротора и подсчета количества импульсов с датчика приращений, реализуем на языке С простейшую утилиту приема данных с платы UNIO по шине ISA…

Реализация тестовой утилиты приема данных с энкодера и визуализация

Прежде всего, на основе схемы (алгоритма) энкодера составим таблицу распределения его выходных сигналов (см. таблицу). Для упрощения написания программы можно воспользоваться библиотечными функциями языка С. В качестве примера рассмотрим фрагмент программы, осуществляющей тестовое считывание данных с контроллера и вывод графического отображения положения ротора датчика PDF. В начале программы необходимо определить адрес считывания, согласно таблице (см. листинг 1):


рисунок

Таблица. Расшифровка выходных сигналов энкодера

код:

пример считывания с портов

int f_dba(int dba,int d[16])
{
   int i,PA;
   for (i=0;i<16;i++)
   {
     PA=inp(BA+dba+i);
     d=PA;
   }
}
// dba- адрес FPGA, d- данные

Адрес считывания по ISA = BA+BAx+Ar, где BA – базовый адрес платы UNIOxx (выставлен 0×110), BAx – базовый адрес матрицы FPGA:

  • для FPGA-1 (BAx=0xA000)
  • для FPGA-2 (BAx=0xA400)
  • для FPGA-3 (BAx=0xA800)
  • для FPGA-4 (BAx=0xAC00)

Рассмотрим подробнее…

Запустим среду Turbo C++ IDE ver.3.0 от Borland и создадим пустой проект. Далее необходимо провести инициализацию графического режима через InitGraph() и зациклить опрос порта INP(). Причем предусмотреть выход из цикла по нажатию определенной комбинации клавиш во время опроса, к примеру, использованием функций Kbhit() и Getch(). В основном цикле необходимо осуществить считывание двухбайтного кода идентификатора схемы, положения ротора, признаков отказа и направления вращения. После чего, произвести отображение выделенных параметров в графическом виде. Оптимальным с точки зрения наблюдения – является имитация положения ротора датчика приращений с выводом дополнительной служебной информации. Реализация подобного подхода представлена в листинге 2:

код:

тестовая программа считывания данных и графического отображения состояний двух датчиков PDF

#include «dos.h»
#include «string.h»
#include
#include
#include
#include
#include
#define BA 0xA110
#define pi 3.14159

int f_dba(int dba,int d[16]);
void main(long int argc, char *argv[])
{
      // переменные порта
      int dba;int d[16];
      // переменные данных
      int FL,ugc,ugc2,FL1,FL2;
      // служебные переменные
      int s,pd,i,nomer,d1,d2;
      long int k,KT,KT2;
      float ugol,ugol2,ug,n,ug2,ug1,KTT,vm,ug_1,ug_2;
      double v,ng1,ng2,nn;
      int gdriver = DETECT, gmode, errorcode;
      char msg[80];
      int x,x2,y,y2,ns,nc,ugg,ugg2,xr,xr2,yr,yr2,wr,wr2,hr,hr2;
      char nbuf[25];
      char kbuf[25];
      char ubuf[25];
      char ibuf[25];
      char sbuf[25];
      char pbuf[25];
      clrscr();
      if(argc>1) // проверка параметров командной строки
      {
          printf(«argc=%d\n»,argc);
          for(i=0;i               printf("%d = %s\n",i,argv);
          if(strcmp(argv[1],»/?») == 0)
          { // выдаем описание
              printf(«Program driver encoder\n»);
          }else if (strcmp(argv[1],»indtest») == 0){}
      }
      //
      clrscr();
      k = 1;
      puts(«Расчитывать параметры по FPGA-?»);
      puts(«Количество импульсов с датчика PDF-?»);
      scanf(«%d %d», &s, &pd); // считываем номер FPGA
      if (s == 1) {dba = 0×0;} // задаем базовый адрес
      if (s == 2) {dba = 0×400;}
      if (s == 3) {dba = 0×800;}
      if (s == 4) {dba = 0xC00;}
      /*Инициализация графического режима*/
      initgraph(&gdriver, &gmode, «»);
      errorcode = graphresult();
      if (errorcode != grOk)
      {
          printf(«Graphics error: %s\n», grapherrormsg(errorcode));
          printf(«Press any key to halt:»);
          getch();
      }
      /*Параметры рисунка*/
      xr=180; // положение 1-го графика
      yr=250;
      xr2=470; // положение 2-го графика
      yr2=250;
      wr=100; // размеры 1-го графика
      hr=100;
      wr2=wr; // размеры 2-го графика
      hr2=hr;
      //
      setfillstyle(1,BLUE);
      fillellipse(xr, yr, wr, hr);
      fillellipse(xr2, yr2, wr2, hr2); // 2-канал
      setcolor(GREEN);
      outtextxy(0,10, «Count:»); // количество импульсов
      outtextxy(0,30, «Angle, deg:»); // угол поворота ротора
      outtextxy(0,41, «Speed, r/s:»); // скорость
      outtextxy(0,52, «HB:»); // направление вращения
      outtextxy(0,63, «delta:»);
      // градусы
      outtextxy(xr+wr+15,yr-5,»0″);
      outtextxy(xr2+wr2+15,yr2-5,»0″);
      outtextxy(xr-wr-40,yr-5,»180″);
      outtextxy(xr2-wr2-40,yr2-5,»180″);
      outtextxy(xr-5,yr-hr-25,»90″);
      outtextxy(xr2-5,yr2-hr2-25,»90″);
      outtextxy(xr-10,yr+hr+15,»270″);
      outtextxy(xr2-10,yr2+hr2+15,»270″);
      do {
          f_dba(dba,d);
          printf(«Опрос:%d», k);
          if (k>1)
          {
              setcolor(BLACK);
              outtextxy(90,10, kbuf);
          }
          setcolor(RED);
          itoa(k, kbuf, 10); // конвертируем в текст (max =10 символов)
          outtextxy(90,10, kbuf);
          /*FPGA_1*/
          printf(«Идентификатор схемы= %c», d[14]); // см. схему
          алгоритма на ПЛИС
          //
          n = ((d[3]<<8)|d[2]);
          if (n < 0) {nn = 65535 + n - 32768;}
          if (n > 0) {nn = n;}
          printf(«Оборот: %7.1f», n);
          if (k>1)
          {
              setcolor(BLACK);
              outtextxy(5,90,nbuf);
          }
          nn=165001;
          setcolor(RED);
          itoa(nn,nbuf,25);
          outtextxy(5,90,nbuf);
          // формируем из двух байт значение положения (см. схему)
          KT = ((d[1]<<8)|d[0]);
          KT2 = ((d[6]<<8)|d[5]);
          ugol = KT;
          ugol2 = KT2;
          // пересчитываем в угловые коорд.положение ротора-1 и ротора-2
          ug = ugol*360/pd;
          ug2 = ugol2*360/pd;
          ugc = ug/360;
          ugc2 = ug2/360;
          ug = 360*(ugc-(ug/360));
          ug2 = 360*(ugc2-(ug2/360));
          ugg = 90-ug;
          ugg2 = 90-ug2;
          if (k>1)
          {
              setcolor(BLACK);
              outtextxy(90,32, ubuf);
              outtextxy(130,32, ibuf);
          }
          setcolor(RED);
          itoa(ug,ubuf,10);
          itoa(ugol,ibuf,10);
          outtextxy(90,32,ubuf);
          outtextxy(130,32,ibuf);
          //
          FL=d[4]&0×04; // определяем направление вращения
          if (k>1)
          {
              if (FL == 0×04) {setcolor(BLACK);outtextxy(90,53,»left»);}
              else {setcolor(BLACK);outtextxy(90,53,»rigth»);}
          }
          if (FL==0×04)
          {
              setcolor(BLACK);outtextxy(90,53,»rigth»);
              setcolor(RED);outtextxy(90,53,»left»);
          }
          else
          {
              setcolor(BLACK);outtextxy(90,53,»left»);
              setcolor(RED);outtextxy(90,53,»rigth»);
          }
          // значение разницы
          if (k>1)
          {
              setcolor(BLACK);
              outtextxy(90,63,pbuf);
          }
          setcolor(RED);
          if (k == 1) {d1 = ug;d2 = ug2;}
          itoa((ug-ug2)*pd/360,pbuf,10);
          outtextxy(90,63, pbuf);
          // скорость вращения
          if (k==1) {ug_1=ug;ng1=ugc;}
          ug_2=ug;ng2=ugc;
          vm = ((ng2-ng1)*360-ug_1+ug_2)/(360*(125e-3));
          printf(«Vm, об/c= %8.6f\n»,vm);
          if (k>1)
          {
              setcolor(BLACK);
              outtextxy(90,43,sbuf);
          }
          setcolor(RED);
          itoa(vm,sbuf,10);
          outtextxy(90,43,sbuf);
          ug1=ug2; ng1=ng2;
          // маркер (вектор на графике)
          if (k>1)
          {
              setcolor(BLUE); // 1-канал
              line(x,y,xr,yr);
              line(x2,y2,xr2,yr2);
          }
          setcolor(RED);
          line(xr-wr-10,yr,xr+wr+10,yr); // ось-x
          line(xr2-wr2-10,yr2,xr2+wr2+10,yr2); // ось-x 2-канал
          line(xr,yr+hr+10,xr,yr-hr-10); // ось-y
          line(xr2,yr2+hr2+10,xr2,yr2-hr2-10); // ось-y 2-канал
          x=xr+(wr*sin(ugg*pi/180)); x2=xr2+(wr2*sin(ugg2*pi/180));
          y=yr+(hr*cos(ugg*pi/180)); y2=yr2+(hr2*cos(ugg2*pi/180));
          setcolor(RED); // 1-канал
          line(xr,yr,x,y);
          line(xr2,yr2,x2,y2);
          // конец маркер
          k+ = 1;
          delay(100);
          if (!kbhit()) s=getch(); // перехватываем нажатую клавишу для
          // останова программы
          if (s==0×9) break;
      } while (s!=0×13);
      closegraph();
      textmode(LASTMODE);
      return;
}

// опрос порта по базовому адресу + смещение
int f_dba(int dba,int d[16])
{
     int i,PA;
     for (i=0; i<16; i++)
     {
         PA = inp(BA + dba + i);
         d = PA;
     }
}

Запустим проект на компиляцию и выполнение командой <Ctrl>+<F9>. При этом, появится экран с запросом параметров считывания (см.рисунок 13). Задав номер FPGA = 3 и максимальное количество импульсов для подключенного датчика = 2048 (для нашего датчика RV-58N), нажмем <ENTER> и получим экран с визуализацией состояний двух энкодеров (см. рисунок 14-15). На рисунке 14 представлен экран состояния датчиков приращений при удаленном просмотре через сеть TCP/IP, но это уже тема отдельной статьи…


рисунок 13

Рис. 13. Экран задания параметров считывания


рисунок 14

Рис. 14. Удаленный просмотр датчиков приращений


рисунок 15

Рис. 15. Экран визуализации состояний двух датчиков PDF

Заключение

Вот в принципе и все. Наслаждаемся аппаратным декодированием состояния шифратора приращений и визуальным просмотром…

Рассматриваемые в данной статье прошивка энкодера для ПЛИС в пакете XILINX 3.1, исходники и компиляция тестовой утилиты визуализации состояния датчика приращений и загрузчик ISP полностью приведены в виде ресурсов в теме «Журнал клуба программистов. Пятый выпуск» или непосредственно в архиве с журналом [4].

Ресурсы

Статья из пятого выпуска журнала «ПРОграммист».
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.

Обсудить на форуме – Энкодер датчика pdf на плис. Часть 2

26th

Библиотека файловой системы AT45DB161

аватар

При разработке микроконтроллерных устройств с внешней памятью типа AT45DBxx приходится сталкиваться с ситуацией, когда блоки данных (файлы) записываются редко, обычно при обновлении ПО устройства, а иногда вообще только один раз – при изготовлении устройства. В таких случаях нет необходимости в использовании файловой системы дискового типа, таких как FAT…

Вячеслав Мовила
http://movilavn.narod.ru

фото

Мовила Вячеслав Викторович


родился 28 июля 1957 г.р., инженер. Интересы: фантастика, читаю много и с увлечением, имею неплохую библиотеку – собирал много лет. Шахматы, к сожалению сейчас не хватает времени. Но самое страстное увлечение и работа – это программирование, основной язык C++, а также, естественно Assembler, Pascal. WEB-программирование, создание динамических, интерактивных сайтов с использованием JavaScript, Java, PHP, MySQL. Базы данных, работа с CASE-средствами разработки информационным систем. Cхемотехника микропроцессорных и микроконтроллерных систем, программирование микроконтроллеров и DSP.

Проще и эффективнее использовать файловую систему последовательного доступа, наподобие ленточной. При этом файлы вместо названия имеют только индексы – последовательный номер файла на устройстве. Данные файла при записи записываются в конец свободного адресного пространства устройства, в этом случае при закрытии файла ему назначается уникальный номер (индекс). Доступ к файлу при чтении происходит по его индексу. На устройстве может находится не более 62 записанных файлов. Рассматриваемая библиотека организует такую файловую систему для микросхемы AT45DB161, порт CodeVision. Листинги библиотеки подробно прокомментированы [1…3]. Так, что при желании не потребуется больших усилий для портирования на другой компилятор и для внесения изменений с целью применения для другого типа микросхем серии AT45DBxx.

Краткое описание AT45DB161

AT45DB161 (см. рис.1) – является Flash памятью с последовательным интерфейсом, и идеально подходит для широкого спектра цифровых голосовых приложений, приложений визуализации, и приложений хранения программного кода и данных. 17 301 504 бит памяти данной ИС организованы в 4096 страниц по 528 байт каждая. Кроме памяти общего назначения ИС, также, имеет два SRAM буфера данных по 528 байт. Буферы обеспечивают возможность приема данных в режиме перепрограммирования страницы основной памяти, или считывание, или запись непрерывных потоков данных. Режим эмуляции EEPROM (с побитным или побайтным изменением) прост в применении, благодаря встроенной, трехступенчатой системе команд Read – Modify – Write. В отличие от стандартных типов Flash памяти, обращение к которым, происходит произвольным образом в режиме многочисленных адресных строк и при помощи параллельного интерфейса, память типа DataFlash использует последовательный интерфейс для обращения к своим данным в режиме последовательного доступа. ИС поддерживает SPI – режимы типа 0 и 3. Простой последовательный интерфейс облегчает разводку платы, увеличивает отказоустойчивость системы, минимизирует коммутационные шумы, а также, уменьшает размер корпуса и число необходимых активных выводов. ИС оптимизирована для использования в широком круге коммерческих и индустриальных приложений, для которых существенную роль играют высокая плотность размещения, малое число выводов, низкое напряжение питания, и низкое энергопотребление. ИС функционирует с тактовыми частотами, вплоть до 20 МГц при типовом потребляемом токе в режиме активного чтения 4 мА.


рисунок 1

Рис. 1. Распиновка ИМС

Предпосылки выбора

Для обеспечения удобства внутрисистемного перепрограммирования, ИС AT45DB161 не требует высоких входных напряжений в режиме программирования. ИС питается от однополярного источника с напряжением от 2.5 В до 3.6 В, или от 2.7 В до 3.6 В, как в режиме программирования, так и в режиме чтения. Выборка ИС AT45DB161 производится по входу CS (активный низкий), а доступ к ИС обеспечивается посредством 3-х проводного последовательного интерфейса, состоящего из сигнала последовательного входа SI, последовательного выхода SO и последовательного тактового сигнала SCK (см. таблицу):

рисунок 2

Таблица. Расшифровка сигналов ИМС

Все циклы программирования имеют встроенный контроль временных характеристик, а для проведения программирования предварительный цикл стирания не требуется. При поставке ИС от Atmel, старшая значащая страница массива памяти может не быть чистой. Другими словами, содержимое последней страницы может быть заполнено содержимым, отличным от FFH.

Отличительные особенности

  • Однополярное напряжение питания от 2.5 В до 3.6 В, или от 2.7 В до 3.6 В
  • Совместимость с последовательным периферийным интерфейсом типа SPI
  • Максимальная тактовая частота 20 МГц
  • Постраничный режим программирования:
  • Одиночный цикл перепрограммирования (стирание плюс программирование)
  • 4096 страниц основной памяти (528 байт на страницу)
  • Поддержка страничного и блочного режимов стирания
  • Два 528-ми байтных буфера данных SRAM, обеспечивающих прием данных в режиме перепрограммирования энергонезависимой памяти
  • Поддержка режима непрерывного считывания полного массива данных
  • Идеально для приложений теневого дублирования кода
  • Низкое энергопотребление:
    4 мА – типичный ток в режиме активного чтения
    2 мкА – типичный потребляемый ток в режиме ожидания
  • Аппаратная функция защиты данных
  • Входы сигналов SI, SCK, CS (активный низкий), RESET (активный низкий) и WP (активный низкий) устойчивы к логическим уровням 5 В
  • Коммерческий и индустриальный диапазоны температур

Схема подключения

рисунок 3

Рис. 2. Схема электрическая принципиальная тестового модуля считывания данных

Несмотря на то, что напряжение питания микросхемы AT45DB161 указано от 2.7 до 3.6 В, микросхема нормально работает при напряжении 5 В. В реальном проекте – используется питание 3 В. Поэтому подключил AT45DB161 на свою макетницу с микроконтроллером ATMega162 с 5-ти вольтовым питанием. Все тесты прошли исключительно хорошо: от самых простых до более сложных – воспроизведение звука с использованием ШИМ- модуляции. Микросхема AT45DB161 использовалась в корпусе SOIC, в котором отсутствует отдельный вывод BYSE, что видно на схеме принципиальной (см. рисунок 2) и было учтено при написании библиотеки.

Структура файловой системы

Первая страница (528 байт) отводится для хранения системной информации о файловой структуре устройства.

Первые 11 байт – это строка *AT45DB161#. Строка является идентификационной записью, которая показывает, что устройство отформатировано и готово к работе. В 12-ом байте содержится число, показывающее количество файлов на устройстве.

Далее идут 8-ми байтовые структуры, выполняющие функцию описателей файлов:

  • в первых 2-х байтах адрес 1-ой страницы файла
  • следующие 2 байта содержат количество страниц в файле
  • последние 4 байта структуры – размер файла в байтах

Функции библиотеки

1. Инициализация файловой системы AT45DB161. unsigned char InitialFlash();
Возвращает значения:
0 – инициализировано.
1 – устройство отсутствует в системе.
2 – устройство не форматировано.

* Комментарий автора.
Внимание! При 6 В быстро выгорает, по крайней мере так было у меня.

2. Форматирование файловой системы AT45DB161 void FormatFlash();

3. Закрыть файл void CloseFile();
4. Открыть файл unsigned char OpenFile(char mode, unsigned char nfile);

Параметр mode:
r – Открыть файл в режиме чтения.
w – Открыть файл в режиме записи.

Параметр nfile:
В режиме чтения указывает индекс (номер) файла. В режиме записи не имеет значения, следует указать 0.

Возвращает значения:
0 – ошибка при открытии файла.
N(1…62) – индекс успешно открытого файла..

После успешного открытия файла будут доступны глобальные переменные статуса файла:

код:

// Переменные описывающие состояние рабочего файла
/*
0 – Файл закрыт
1 – Файл открыт в режиме записи
2 – Файл открыт в режиме чтения
*/
unsigned char at45_file_mode = 0;
// Счетчик страниц при записи
unsigned int at45_cpwrite = 0;
// Номер текущей страницы
unsigned int at45_npage = 0;
// Индекс открытого файла
unsigned char at45_currfile = 0;
// Размер открытого файла/счетчик байт откр. файла при записи
unsigned long at45_cbfile = 0;
// Счетчик байт открытого файла при чтении
unsigned long at45_countb = 0;
// К-во страниц в файле
unsigned int at45_kpage = 0;
// Счетчик байт записанных/считанных в/из буфер
unsigned int at45_buffer_counter = 0;

5. Считать из файла count байт в буфер dest unsigned int ReadFile(char * dest, unsigned int count);

dest – Указатель на буфер чтения.
count – Количество байт для считывания.

Возвращает значения:
N – количество считанных байт.

6. Записать в файл count байт из буфера source. unsigned int WriteFile(char * source, unsigned int count);
source – Указатель на буфер записи.
count – Количество байт для записи.

7. Читать файл побайтно unsigned char ReadByte(unsigned char * flag);

flag – Указатель на переменную типа unsigned char. При чтении первого байта должен из вызывающей функции установлен в 0. При успешном чтении байта внутри функции ReadByte устанавливается в 1. При ошибке чтения или достижении конца файла внутри функции ReadByte устанавливается в 2.

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

Применение библиотеки

Для того, чтобы использовать библиотеку в проект ПО следует включить файлы: <at45db161.c> и <at45db161.h>. В файле <at45db161.h> следует скорректировать 2 настройки:

Первая:
код:

// DataFlash chip select
// Здесь следует определить пин порта мк. для CS AT45DB161!!!
#define DF_CHIP_SELECT PORTC.0

В строке 7 указать бит порта вывода который Вы будете использовать в качестве сигнала CS микросхемы AT45DB161:

Вторая:

Переопределить настройки интерфейса SPI в строке 38:

код:

// Здесь следует определить настройки SPI!!!
// Включить SPI.
// SPI initialization
// SPI Type: Master
// SPI Clock Rate: 4000.000 kHz
// SPI Clock Phase: Cycle Start
// SPI Clock Polarity: High
// SPI Data Order: MSB First
#define SPI_ON SPCR=0x5c

Простой пример применения библиотеки:

код:

unsigned char temp;

temp = InitialFlash();

if(temp) {
     if(temp == 1) {
         // И зацикливаемся – ус-во не обнаружено в системе
         while(1);
     }
     // ИНАЧЕ УСТРОЙСТВО ОБНАРУЖЕНО НО НЕ ФОРМАТИРОВАННО!
     // ФОРМАТИРУЕМ FLASH
     FormatFlash();
}

// Записали первый файл:
OpenFile(‘w’, 0);
memset(Buff, 0, 128);
for(ic = 0;ic<256;ic++) Buff[ic] = ic;
WriteFile(Buff, 256);
WriteFile(Buff, 256);
WriteFile(Buff, 256);
WriteFile(Buff, 256);
WriteFile(Buff, 256);
CloseFile();

// Записали второй файл:
OpenFile('w', 0);
memset(Buff, 2, 128);
//for(ic = 0;ic<256;ic++) Buff[ic] = ic;
WriteFile(Buff, 128);
WriteFile(Buff, 55);
CloseFile();

// Записали третий файл:
OpenFile('w', 0);
memset(Buff, 3, 128);
//for(ic = 0;ic<256;ic++) Buff[ic] = ic;
WriteFile(Buff, 128);
WriteFile(Buff, 23);
CloseFile();
// Считали третий файл:
If (OpenFile(‘r’, 3)) {
     do {
         memset(Buff, 0, 528);
         ic = ReadFile(Buff, 64);
     } while(ic);
     CloseFile();
}
//Считали второй файл:
if(OpenFile(‘r’, 2)) {
     do {
         memset(Buff, 0, 528);
         ic = ReadFile(Buff, 64);
     } while(ic);
     CloseFile();
}

// Считали первый файл:
if(OpenFile(‘r’, 1)) {
     memset(Buff, 0, 528);
     do {
         ic = ReadFile(Buff, 64);
     } while(ic);
     CloseFile();
}

Заключение

Как видите, использование библиотеки последовательного доступа значительно упрощает разработку целого ряда устройств с голосовым сопровождением на основе Flash- памяти.

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

*** Комментарий автора.
Программа, которая умеет открывать файлы мультимедиа типа WAV, идентифицировать их, на соответствии требованиям закачки (частота дискретизации, количество каналов и т.д.) и пересылать их в микроконтроллерную систему.

Рассматриваемые в данной статье исходники библиотеки файловой системы последовательного доступа полностью приведены в виде ресурсов в теме «Журнал клуба программистов. Пятый выпуск» или непосредственно в архиве с журналом.

Ресурсы

Статья из пятого выпуска журнала «ПРОграммист».
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.

Обсудить на форуме – Библиотека файловой системы AT45DB161

26th

Рассылка. Выпуск 73

redaktor От ведущего.

Доброй ночи читатели рассылки. Сегодняшняя рассылка получилась очень содержательной, много тем с форума, статьи с журнала “ПРОграммист”. Подходит к концу жаркое лето, многие форумчане возвращаются с отпусков и общение в нашем клубе становится более насыщенным.

logo_grey

Новые интересные статьи клуба программистов.

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

 


Регистры и смещение

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


Динамическое меню на сайте с помощью php

Реализация динамического вложенного меню на php (пункты меню хранятся в файле).
Тема на форуме


Олимпийские игры для роботов стартовали в Китае

Роботы из разных стран соревнуются между собой в футболе, прыжках в высоту, баскетболе, боксе и даже в танцах и игре на барабанах. В Технологическом университете города Харбин в Китае проходят первые в истории Олимпийские игры среди человекоподобных роботов. Размеры спортсменов варьируются от 20 см до полуметра. Большинство роботов собраны вручную, из простых деталей.


Полупрозрачность в Delphi

И так, как сделать окошко в дельфи прозрачным с красивыми тенями и другой мутью.
Тема на форуме


Как в ListView показывать/прятать колонки?

Тема на форуме


Беспроводная сеть масштаба микрорайона. Часть 1

Общаясь с друзьями и знакомыми, работающими в области ИТ, не раз приходилось слышать заявление, что Wi-Fi подходит только для сетей масштаба квартиры или небольшого офиса. В качестве аргументов приводились малая дальность, зависимость от погодных условий, ненадежность оборудования. Примерно такое же мнение бытует о том, что для провайдерских сетей не подходит платформа Windows. Аргументы: высокая ресурсоемкость, ненадежность и вообще неспособность работать в качестве системы биллинга.


Как развернуть flash-приложение во весь экран?

Тема на форуме


Определить нажата правая клавиша мыши?

Событие OnMouseDown у формы, проверяя таким макаром:
код:

if Button=mbRight then Form2.ShowModal;

Тема на форуме


Как узнать количество строк в memo?

У новичков может возникнуть такой вопрос.
код:

a := Memo1.Lines.Count;// кол-во строк Memo1

Нумерация строк начинается с нуля.
Тема на форуме


Пример установки разрешения 1152х864 под Windows. asm

Тема на форуме


Получить идентификатор процесса и узнать полуный путь до файла этого процесса. c/c++

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


Как в WebBrowser выбрать из списка и нажать на кнопку?

Тема на форуме


Как отключить загрузку картинок в Firefox?

Тема на форуме


Делаем динамические тени на OPENGL. Часть 1

Здравствуйте. В этой статье я хочу рассмотреть создание движка динамического освещения с помощью графической библиотеки OpenGL. Писаться движок будет на Delphi, но это не мешает переписать его на любой другой язык, так как главное, рассматриваемое в статье, это алгоритмы…


Создание логотипа для журнала ПРОграммист

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

Внимание!
Логотип будет размещаться в левом верхнем углу, там где надпись “ПРОграммист” на каждой странице

Следовательно, исходить нужно из этих предпосылок, т.е. не делать мелких деталей.
Кроме того, нужен логотип-баннер (для обмена ссылками) журнала

Его тоже можно здесь выкладывать.
Тема на форуме


Энкодер датчика pdf на плис. Часть 2

Итак, сегодня мы с вами продолжим наш материал по промышленной автоматизации, рассмотрим реализацию алгоритма энкодера на ПЛИС, особенности прошивки модулей Faswell UNIOxx-5 и создадим тестовую утилиту визуализации состояния шифратора приращений.


Библиотека файловой системы AT45DB161

При разработке микроконтроллерных устройств с внешней памятью типа AT45DBxx приходится сталкиваться с ситуацией, когда блоки данных (файлы) записываются редко, обычно при обновлении ПО устройства, а иногда вообще только один раз – при изготовлении устройства. В таких случаях нет необходимости в использовании файловой системы дискового типа, таких как FAT…


Исскуство изменеия GTA

Здравствуйте, любители гейминга. В данной статье, я хочу показать, как делаются плагины для всем известной GTA. Начнем мы самого простого – это программирование плагинов на Delphi для Grand theft Auto ViceCity. А поняв принцип их работы, никакого труда не составит написать плагин и для других серий GTA…


На сайте клуба есть рубрики пост-обзор и топик-обзор клуба программистов.

ev
Немного юмора.

***
Работа пpогpаммиста и шамана имеет много общего – оба боpмpчyт непонятные слова, совеpшают непонятные действия и не могyт объяснить, как оно pаботает.

***
Доктор ставит хакеру диагноз:
- Итак, дорогой, вам осталось жить 30 дней.
- Извините, доктор, а где можно скачать crack?

***
Для ухода за пожилым программистом требуется приятная женщина, говорящая на BASIC, PASCAL и C++.

***
Письмо в службу технической поддержки: “У МеНя мИгАеТ ИнДиКаТоР cApS LoCk, кАк эТо лЕчИтСя?”

***
Одна барышня звонила на какую-то фирму и ругалась, что они ей какой-то не такой софт подсунули, что он не инсталлируется, хотя она все, мол, делает в соответствии с инструкцией (а софт ентот с дискет ставился). Ну, послали спеца из фирмы, продавшей этот софт, на месте разобраться – what’s, собственно, up…
Приехал он, а барышня ему и говорит:
- Вот у вас в инструкции написано – “вставьте дискету №1″, ну, я вставила, потом написано “вставить дискету №2″, ну, – говорит, – я ее вставила, потом – “дискету №3″, ну, вставила я ее (с трудом, правда), но вот дискета №4 уже просто в дисковод не лезет!!!

***
Объявлено об объединении “Микрософт” и “Линукс”. Эмблемой новой системы выбран пингвин, выпадающий в окно.

Посетите раздел юмора на форуме, который обновляется постоянно

Читать этот номер в клубе.

25th
Авг

Создание логотипа для журнала ПРОграммист

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

Внимание!
Логотип будет размещаться в левом верхнем углу, там где надпись “ПРОграммист” на каждой странице

Следовательно, исходить нужно из этих предпосылок, т.е. не делать мелких деталей.
Кроме того, нужен логотип-баннер (для обмена ссылками) журнала

Его тоже можно здесь выкладывать.

Присоединяйтесь

25th

Делаем динамические тени на OPENGL. Часть 1

аватар

Здравствуйте. В этой статье я хочу рассмотреть создание движка динамического освещения с помощью графической библиотеки OpenGL. Писаться движок будет на Delphi, но это не мешает переписать его на любой другой язык, так как главное, рассматриваемое в статье, это алгоритмы…

Вадим Буренков
vadim_burenkov@mail.ru

Чтобы не тратить время на инициализацию OpenGL и избежать других проблем (например, с настройкой таймеров и рендера в текстуру) я буду использовать движок ZenGL [1]. Впрочем, от него нам многого не понадобится. Итак, приступим…

Инициализация OpenGL в ZenGL

Первым делом качаем ZenGL и создаем в нем простейшее приложение (вы можете найти его в папке LightEngine ресурсов статьи, там же вы найдете ZenGL):

код:

program LightEngine;
uses
   zgl_main,
   zgl_screen,
   zgl_window,
   zgl_timers,
   zgl_textures,
   zgl_textures_jpg,
   zgl_sprite_2d,
   zgl_mouse,
   zgl_keyboard,
   zgl_utils;
var
   BackTex:zglPTexture; // текстура фона
   bTiles:zglTTiles2D; // параметры тайлинга

procedure Init;
var n,j:integer;
begin
   // отключаем очищение буфера
   zgl_disable(COLOR_BUFFER_CLEAR );
   // Тут можно выполнять загрузку основных ресурсов
   // загрузка текстуры и настройка тайлинга
   BackTex:=tex_LoadFromFile( ‘Back.jpg’,0,TEX_DEFAULT_2D);
   // параметры тайлов фона
   bTiles.Count.X:=7;
   bTiles.Count.Y:=5;
   bTiles.Size.W:=128;
   bTiles.Size.H:=128;
   SetLength(bTiles.Tiles,7,5);
&nfor fto=0 to 4 do
&nbsforbsp;&ntob>for
j:=0 to 6 do bTiles.Tiles[j,n]:=1;
end;

procedure Draw;
begin
   // Тут «рисуем» что угодно :)
   tiles2d_Draw(BackTex,0,0,BTiles); // отрисовка фона
end;

procedure Update;
begin
   // Тут выполняется обработка данных
   if key_Press( K_ESCAPE ) then zgl_Exit;
   // обновление клавиш
   key_ClearState;
   Mouse_ClearState;
end;

procedure Timer;
begin
   // Будем в заголовке показывать количество кадров в секунду
   wnd_SetCaption( ‘LightEngine [ FPS: ' + u_IntToStr( zgl_Get(
   SYS_FPS ) ) + ' ]‘ );
end;

procedure Quit;
begin
   // Тут выполняется очищение данных
end;

Begin
   // Создаем таймер с интервалом 1000мс.
   timer_Add( @Timer, 1000 );
   // Создаем таймер с интервалом 10мс.
   timer_Add( @Update, 10 );
   // Регистрируем процедуру, что выполнится сразу после
   // инициализации ZenGL
   zgl_Reg( SYS_LOAD, @Init );
   // Регистрируем процедуру, где будет происходить рендер
    zgl_Reg( SYS_DRAW, @Draw );
    // Регистрируем процедуру, которая выполнится после завершения
    // работы ZenGL
    zgl_Reg( SYS_EXIT, @Quit );
    // Устанавливаем заголовок окна
    // Разрешаем курсор мыши
    wnd_ShowCursor( TRUE );
    // Указываем первоначальные настройки
    scr_SetOptions( 800, 600, REFRESH_MAXIMUM, FALSE, FALSE );
    // Инициализируем ZenGL
    zgl_Init;
End.

При инициализации мы указываем процедуры в которых будут производится различные действия (инициализация/обработка/очищение) а также параметры окна.

В инициализации загружается текстура и настраивается тайлинг (количество и размер настроен так, чтобы текстура закрывала весь экран). В обработке обновляются состояния мыши и клавиатуры, а также стоит проверка на нажатие ESC. Процедура очищения пока пуста, так как ресурсы движка очищаются самостоятельно.

Другие непонятные процедуры можно посмотреть в справке, которая находится в папке doc движка. Чтобы при компиляции не возникло проблем необходимо указать расположение модулей движка в Project->Options- >Directories/Conditionals->SearchPath, а именно папки zengl/src и zengl/src/PasZLib (см. рис.1). Можно скомпилировать проект, увидеть вы должны следующее (см. рис.2).

рисунок 1

Рис. 1. Пути

рисунок 2

Рис. 2. Тайлинг

Немного теории

Теперь перейдем к теории вопроса. В движке мы должны реализовать два типа – источники света и объекты, которые отбрасывают тени (см. рис.3):

рисунок 3

Рис. 3. Тень от объекта

Источник света обладает параметрами:

  • положение
  • радиус
  • цвет
  • интенсивность

Все объекты являются невыпуклыми многоугольниками. Они имеют:

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

Локальные координаты нужны, так как через положение и угол поворота объекта его можно разворачивать.

Для хранения данных об освещенности нам понадобятся два буфера размером в экран. Первый – альфа буфер. В него выводится круглый источник света (см. рис.4):

рисунок 4

Рис. 4. Источник света

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

рисунок 5

Рис. 5. Смешивание источников света

В нем светлые участки – там где свет, а темные – там где тьма. А теперь мы выводим буфер аккамуляции на экран с блендингом MULT. Получается так, что чем светлее цвет, тем он прозрачнее (см. рис.6):

рисунок 6

Рис. 6. Рисование с блендингом MULT

Как же делаются тени от объектов? При выводе источника света в альфа буфер на него рисуется форма тени черным цветом. Получается что от круга света «отрезают» кусок (см. рис.7):

рисунок 7

Рис. 7. Форма тени на свете

С помощью такого алгоритма получаются тени любой сложности, причем их количество, как и источников света с объектами неограниченно (см.рис.8).

Да будет свет!

Под следующий код сделаем модуль, который и будет отвечать за тени. Назовем его ZGLShadows.

рисунок 8

Рис. 8. Сцена с большим количеством теней

Напишем тип света:

код:

type
   PLightSource=^TLightSource;
   TLightSource=record
   position:leVect; // положение
   radius:single; // радиус
   color:TColorRGB; // цвет
   intensivity:single; // интенсивность cвета
   prev,next:PLightSource;
end;

Все данные будут храниться в “prev-next” (двухсвязных) списках (см. рис.9):

рисунок 9

Рис. 9. Списки

Каждый элемент является звеном цепи и имеет указатели на предыдущее и следующее звено. Нам же нужно иметь первый элемент и длину цепи для управления списком:

код:

Var
   // Источники света
   le_Lights:PLightSource; // список
   le_NumLights:integer; // количество

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

код:

type
   TColorRGB=record
   r,g,b:single;
end;

Данный тип нужен для хранения цвета в формате rgb, так как его использует OpenGL. ZenGL использует integer для хранения цветов (например $FFFFFF соответствует 1,1,1 в RGB), поэтому нам может понадобится процедура для перевода цвета в RGB:

код:

function IntToRGB(Color:Integer): TColorRGB;
begin
   Result.r := ((Color and $FF0000) shr 16) / 255;
   Result.g := ((Color and $FF00) shr 8) / 255;
   Result.b := (Color and $FF) / 255;
end;

Все координаты будут храниться в типе:

код:

type
   leVect=record
   x,y:single;
end;

Подробнее о нем будет написано позже, пока нам понадобится только формирование вектора по x и y:

код:

function le_v(x,y:single):leVect;
begin
   result.x:=x;
   result.y:=y;
end;

Перейдем к процедурам управления источниками света:

код:

Function le_CreateLightSource(p:leVect; radius,intensivity:single;
                                color:TColorRGB):PLightSource;
var t: PLightSource;
begin
   new(t);
   t.Next:= nil;
   t.Prev:= nil;
   t.position:=p;
   t.radius:=radius;
   t.intensivity:=intensivity;
   t.color:=color;
   t.Next:= le_Lights;
   if le_Lights <> nil then le_Lights.Prev:= t;
   le_Lights:= t;
   Result:= le_Lights;
   inc(le_NumLights);
end;

Функция создает источник света в памяти и возвращает указатель на него. Большую часть кода занимает работа со списками.

В следующей процедуре происходит рисование круга света как на рисунке 4. Он рисуется через GL_TRIANGLE_FAN. Первая точка в центре имеет цвет и интенсивность света, далее идут точки по радиусу окружности с нулевым цветом, благодаря чему мы имеем плавный переход цвета:

код:

procedure le_DrawLightSource(t:PLightSource);
var angle:single;
begin
   angle:=0;
   glBegin(GL_TRIANGLE_FAN);
   glColor4f(t.color.r, t.color.g, t.color.b, t.intensivity);
   glVertex2f(t.position.x,t.position.y);
   glColor4f(0, 0, 0, 0 );
   while angle<=Pi*2 do begin
     glVertex2f( t.radius*cos(angle) + t.position.x,
     t.radius*sin(angle) + t.position.y);
     angle:=angle+((PI*2)/le_numSubdivisions);
   end;
   glVertex2f(t.position.x+t.radius, t.position.y);
   glEnd();
end;

Количество треугольников, из которого рисуется круг, задается константой:

код:

const
   le_numSubdivisions = 32;

Следующая процедура рассчитывает и рисует тень для объектов, но о ней я напишу позже:

код:

procedure le_RenderShadowGeometry(t:PLightSource);

Далее напишем процедуру, которая освобождает память, занятую источником света:

код:

procedure le_FreeLightSource(t:PLightSource);
var DelT: PLightSource;
begin
   DelT:= t;
   if t.Prev <> nil then t.Prev.Next := t.Next
   else le_Lights:= t.Next;
   if t.Next <> nil then t.Next.Prev := t.Prev;
   Dispose(DelT);
   dec(le_NumLights);
   t:=nil
end;

Следующая процедура вспомогательная, она обрабатывает каждый источник света передаваемой в нее процедурой:

код:

procedure le_EachLightSource(p:le_proc);
var t, tNext: PLightSource;
begin
   t:= le_Lights;
   while t <> nil do
   begin
     tNext:= t.Next;
     p(t);
     t:= tNext;
   end;
end;

le_proc – тип процедуры:

код:

type
   le_proc=procedure(d:Pointer);

Например, данная строчка нарисует все источники света:

код:

le_EachLightSource(@le_DrawLightSource);

Хочу заметить, что при попытке передать в le_EachLightSource процедуру очищения возникнет ошибка, связанная с памятью, поэтому для очищения всех источников света напишем отдельную процедуру:

код:

procedure le_FreeAllLightSources;
var t, tNext: PLightSource;
begin
t:= le_Lights;
while t <> nil do begin
tNext:= t.Next;
le_FreeLightSource(t);
t:= tNext;
end;
end;

Заставим это работать

С типом света мы управились, теперь надо заставить его работать. Объявим следующие переменные:

код:

var // Движок
   le_AlphaBuffer: zglPRenderTarget; // буфер для света
   le_AccBuffer: zglPRenderTarget; // буфер для сложения
   // изображений света
   le_DarkColor: integer; // цвет тени

В этой процедуре инициализируются буферы для рендеринга. К проекту нужно также подключить модули:

  • zgl_textures – создание текстуры-буфера
  • zgl_render_target – управление рендерингом
  • zgl_primitives_2d – очищение рендер target. Хотя можно было бы просто рисовать QUAD на OpenGL.
  • zgl_fx – процедуры управления блендингом
  • zgl_sprite_2d – рисование текстур

Напишем процедуру инициализации буферов:

код:

procedure le_InitLightEngine(DarkColor:Integer);
begin
   le_DarkColor:=DarkColor;
   // инициализация буферов
   le_AlphaBuffer:=rtarget_Add( RT_TYPE_FBO, tex_CreateZero(
     800,600, 0, TEX_DEFAULT_2D ) , RT_FULL_SCREEN );
   le_AccBuffer :=rtarget_Add( RT_TYPE_FBO, tex_CreateZero(
     800,600, 0, TEX_DEFAULT_2D ) , RT_FULL_SCREEN );
end;

le_DarkColor – переменная, которая отвечает за освещенность. К ее смыслу и принципу работы я еще вернусь. Обобщающая процедура полной обработки света:

код:

procedure le_RenderLight(t:PLightSource);
begin
   rtarget_Set( le_AlphaBuffer ); // начинаем рендер в буфер
   pr2d_Rect(0,0,800,600, 0,255,PR2D_FILL); // очищаем черным
   // цветом
   le_DrawLightSource(t); // отрисовка источника света
   rtarget_Set( nil );
   rtarget_Set( le_AccBuffer ); // отрисовка полученного
   // изобр-я в буфер аккамуляции
   fx_SetBlendMode(FX_BLEND_ADD); // при отрисовке используем
   // блендинг для сложения
   // интенсивностей источ-в света
   ssprite2d_Draw( le_AlphaBuffer.Surface, 0,0,800,600,0);
   fx_SetBlendMode(FX_BLEND_NORMAL);
   rtarget_Set( nil );
end;

И завершающая процедура – вывод буфера с использованием MULT блендинга:

код:

procedure le_FinishRender;
begin
   // выводим полученные тени и свет на экран с использованием
   // блендинга mult (чем светлее изображение тем прозрачней)
   fx_SetBlendMode(FX_BLEND_MULT);
   ssprite2d_Draw( le_AccBuffer.Surface, 0,0,800,600,0);
   fx_SetBlendMode(FX_BLEND_NORMAL);
   // очищаем буфер для следующего кадра (цветом le_DarkColor!)
   rtarget_Set( le_AccBuffer );
   pr2d_Rect(0,0,800,600, le_DarkColor,255,PR2D_FILL);
   rtarget_Set( nil );
end;

Хочу заметить, что очищение le_AccBuffer проводится цветом le_DarkColor. Следовательно, чем светлее этот цвет тем прозрачнее тени (см. рис.10). На изображении видно, что справа фон просвечивается даже там, где света нет, так как le_DarkColor не черный, а серый ($1f1f1f).

рисунок 10

Рис. 10. Различный DarkColor

Все, система света написана. Правда, пока без теней от объектов. Теперь проверим ее в действии.
Добавим переменную под управляемый свет:

код:

var
   UserLight:PLightSource; // указатель на управляемый свет

Создадим его, и еще 4 света в Init:

код:

   le_InitLightEngine(0); // инициализируем световой движок
   // загружаем источники света
   le_CreateLightSource
   (le_v(520,550),400,0.3,IntToRGB($FF00FF));
   le_CreateLightSource
   (le_v(470,50),250,0.5,IntToRGB($FF0000));
   le_CreateLightSource
   (le_v(200,300),270,1,IntToRGB($00FF00));
   le_CreateLightSource
   (le_v(640,270),300,0.8,IntToRGB($FFFFFF));
   UserLight:=le_CreateLightSource(le_v(0 ,
   0),100,0.8,IntToRGB($FFFFFF));

Теперь в Draw напишем рисование теней:

код:

   // обработка всех источников света
   le_EachLightSource(@le_RenderLight);
   // отрисовка теней
   le_FinishRender;

В Update привяжем UserLight к мышке, сделаем изменение размера при нажатии на кнопки мыши и цвета при нажатии на колесико:

код:

   if mouse_Down( M_BLEFT ) then
   UserLight.radius:=UserLight.radius+3;
   if mouse_Down( M_BRIGHT ) then
   if UserLight.radius>0 then
   UserLight.radius:=UserLight.radius-3;
   if mouse_Click( M_BMIDLE ) then begin
   UserLight.color.r:=random(100)/100;
   UserLight.color.g:=random(100)/100;
   UserLight.color.b:=random(100)/100;
end;

И наконец, в Quit очищаем источники света:

код:

   le_EachLightSource(@le_FreeLightSource);

Запускаем, любуемся результатом (см. рис.11).

рисунок 11

Рис. 11. Результат

Заключение

В следующей части статьи я рассмотрю создание теней от объектов, а также оптимизирую код, чтобы добиться большей производительности. Весь исходный код проекта приложен к журналу «ПРОграммист. Пятый выпуск».

Продолжение следует…

Ресурсы

  • Страница разработчика ZenGL http://andrukun.inf.ua/zengl.html
  • Михалкович С.С. Основы программирования.
  • Второй семестр 08-09, 2 часть

Обсудить на форуме – Делаем динамические тени на OPENGL. Часть 1

24th
Авг

Как отключить загрузку картинок в Firefox?

pu4koff:

Инструменты / Настройки / Содержимое / Автоматически загружать изображения

Тема на форуме

24th

Как в WebBrowser выбрать из списка и нажать на кнопку?

Posted by Chas under Пост-обзор

zlodey:

Нажатие на кнопку:
код:

procedure PSpisokClick;
var HtmlDocument : IHtmlDocument2;
   i : integer;
   HtmlCollection : IHtmlElementCollection;
   HtmlElement : IHtmlElement;
   spisok : string;
begin
   HtmlDocument := BrowserMain.Document as IHtmlDocument2;
   HtmlCollection := HtmlDocument.All;
   for i := 0 to HtmlCollection.length – 1 do
   begin
     if stop = 1 then Exit;
     HtmlElement := HtmlCollection.Item(i, 1) as IHtmlElement;
     spisok := HtmlElement.InnerText;
     Trim(spisok);
     if spisok = ‘список’ then
     begin
       HtmlElement.click;
       Exit;
     end;
   end;
end;

выбор из открывающегося списка:
код:

procedure SetFieldValue(theForm: IHTMLFormElement;
const fieldName, newValue: string; const instance: integer);
var
   field: IHTMLElement;
   inputField: IHTMLInputElement;
   selectField: IHTMLSelectElement;
   textField: IHTMLTextAreaElement;
begin
   field := theForm.Item(fieldName,instance) as IHTMLElement;
   if Assigned(field) then
   begin
     if field.tagName = ‘INPUT’ then
     begin
       inputField := field as IHTMLInputElement;
       if (inputField.type_ ‘radio’) and (inputField.type_ ‘checkbox’)
       then inputField.value := newValue
       else inputField.checked := (newValue = ‘checked’);
     end
     else if field.tagName = ‘SELECT’ then
     begin
       selectField := field as IHTMLSelectElement;
       selectField.value := newValue;
     end
     else if field.tagName = ‘TEXTAREA’ then
     begin
       textField := field as IHTMLTextAreaElement;
       textField.value := newValue;
     end;
   end;
end;

вызов процедуры:
код:

theForm := GetFormByNumber(BrowserMain.Documen t as IHTMLDocument2,0);
SetFieldValue(theForm,’type’,переменная);

Тема на форуме

23rd
Авг

Получить идентификатор процесса и узнать полуный путь до файла этого процесса. c/c++

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

код:

#include <windows.h>
#include <stdio.h>
#include <TlHelp32.h>
#include <conio.h>
#include <string.h>
#include <psapi.h>

using namespace std;

int main()
{
   HANDLE h,hp;
   PROCESSENTRY32 pe;
   int id;
   bool bl,flag=false;
   char name[256],str[256];
   char path[MAX_PATH];
   DWORD dw;
   HMODULE hmod;

   scanf(”%s”,name);

   h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS|TH32CS_SNAPMODULE,0);

   for(bl = Process32First(h, &pe); bl; bl = Process32Next(h, &pe))
   {
      strcpy(str,pe.szExeFile);
      if(strcmp(str,name)==0)
      {
        printf(”Process found: %s\n”,str);
        hp = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,pe.th32ProcessID);
         EnumProcessModules(hp, &hmod,sizeof(hmod),&dw); // получаем первый модуль, связанный с процессом, то есть сам exe-файл
         GetModuleFileNameEx(hp, hmod, path, MAX_PATH); // получаем путь к модулю

         printf(”path: %s\n”,path);

         CloseHandle(hp);
         CloseHandle(h);
         flag = true;
         break;
      }
   }
   CloseHandle(h);
   if(!flag) printf(”Process not found”);

   getch();
   return 0;
}

Нужно прилинковать модуль psapi.

Тема на форуме

23rd

Как узнать количество строк в memo?

У новичков может возникнуть такой вопрос.
код:

a := Memo1.Lines.Count;// кол-во строк Memo1

Нумерация строк начинается с нуля.

Тема на форуме

23rd

Определить нажата правая клавиша мыши?

Событие OnMouseDown у формы, проверяя таким макаром:

код:

if Button=mbRight then Form2.ShowModal;

Тема на форуме

23rd

Как развернуть flash-приложение во весь экран?

Kotofff:
Компонент которым показываешь (проигрываешь) флеш-ролик в программе выравнивай на всю форму, а с самой формой можно так :

код:

procedure TForm1.FormCreate(Sender: TObject);
var
   HTaskbar: HWND;
   OldVal: LongInt;
begin
   try
     HTaskBar := FindWindow(’Shell_TrayWnd’, nil);
     SystemParametersInfo(97, Word(True), @OldVal, 0);
     EnableWindow(HTaskBar, False);
     ShowWindow(HTaskbar, SW_HIDE);
   finally
     with Form1 do
     begin
       BorderStyle := bsNone;
       FormStyle := fsStayOnTop;
       Left := 0;
       Top := 0;
       Height := Screen.Height;
       Width := Screen.Width;
     end;
   end
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
   HTaskbar: HWND;
   OldVal: LongInt;
begin
   HTaskBar := FindWindow(’Shell_TrayWnd’, nil);
   SystemParametersInfo(97, Word(False), @OldVal, 0);
   EnableWindow(HTaskBar, True);
   ShowWindow(HTaskbar, SW_SHOW);
end;

Тема на форуме

22nd
Авг

Беспроводная сеть масштаба микрорайона. Часть 1

аватар

Общаясь с друзьями и знакомыми, работающими в области ИТ, не раз приходилось слышать заявление, что Wi-Fi подходит только для сетей масштаба квартиры или небольшого офиса. В качестве аргументов приводились малая дальность, зависимость от погодных условий, ненадежность оборудования. Примерно такое же мнение бытует о том, что для провайдерских сетей не подходит платформа Windows. Аргументы: высокая ресурсоемкость, ненадежность и вообще неспособность работать в качестве системы биллинга.

Александр
by WildHunter http://airnet.sytes.net

А так ли это? Этот вопрос нас всерьез заинтересовал и подтолкнул к попытке создания беспроводной сети как раз на базе Wi-Fi и Windows. Оговорюсь, что некоторый опыт создания беспроводных сетей у нас уже был, правда, немного другого назначения – корпоративных.

Начали мы естественно с постановки самим себе техзадания:

  1. Сетевая технология WiFi IEEE 802.11b/g, возможно в будущем 802.11a и 802.11n википедия
  2. Серверы на базе Windows Server. В качестве основной ОС был выбран Windows Server 2003, как достаточно надежная и неприхотливая система, при этом обеспечивающая нужный функционал википедия
  3. Максимальная простота развертывания, эксплуатации и администрирования сети.
  4. Минимальные затраты, поскольку проект некоммерческий и финансирования со стороны не будет, придется обходиться собственными силами и средствами.
  5. Надежность, производительность и пропускная способность, достаточные для обслуживания городского микрорайона.

Выбор оборудования

Основательно изучив рынок предложений недорогого Wi-Fi оборудования, мы остановили свой выбор на нескольких моделях точек доступа (ТД) от D-Link: DWL-2100AP, DAP-1150 и DAP-1160 http://www.d-link.ru. Основными причинами выбора именно этих точек стали их приемлемая цена, накопленный в России и на Украине большой опыт их эксплуатации, а также наличие большого количества альтернативных прошивок, как от различных производителей оборудования, так и open-source.

Для тестирования было закуплено несколько экземпляров указанных выше точек доступа, а также различных антенн к ним. Началось тестирование в различных режимах, на разных расстояниях, с различными антеннами и прошивками. От «родных» прошивок мы отказались практически сразу, поскольку они рассчитаны как раз на применение в домашних или условиях небольшого офиса, не позволяют менять многие важные параметры (ACK timeout, мощность передатчика, чувствительность приемника и т.д.), а также практически не обеспечивают возможности мониторинга беспроводных соединений.

Точки DWL-2100AP оказались хороши для построения мостов на большие расстояния (до 50 км), но капризными в эксплуатации и несовместимыми со многими другими моделями Wi-Fi устройств. Также у них обнаружилась неприятная проблема: довольно часто при большой нагрузке «слетали» прошивки, а их восстановление оказалось довольно непростой процедурой. В итоге DWL-2100AP была признана нами годной к применению только для организации мостов. Хотя вполне возможно, что нам просто достались неудачные экземпляры.

DAP-1150 – очень простое и надежное устройство, тем не менее отвечающее всем основным критериям хотспота. А с немного доработанной прошивкой от Conceptronic http://www.conceptronic.net эта точка стала практически полностью соответствовать нашим требованиям.

рисунок 1

Рис. 1. Точка доступа DAP-1150

Основные характеристики DAP-1150 с прошивкой Conceptronic:

  • Стандарты: 802.11b/g, 802.3/802.3u 10Base- T/100Base-TX Ethernet, ANSI/IEEE 802.3 NWay auto-negotiation.
  • Интерфейсы: 802.11b/g беспроводная LAN, 1 порт 10/100Base-TX Ethernet LAN
  • Диапазон частот: 2.4 – 2.4835 ГГц
  • Количество каналов: 13 (ETSI)
  • Схемы модуляции:
    802.11b: DQPSK, DBPSK, DSSS, CCK
    802.11g: BPSK, QPSK, 16QAM, 64QAM, OFDM
  • Режимы работы: Station – Ad Hoc, Station – Infrastructure, AP, AP Bridge – Point to Point, AP Bridge – Point to MultiPoint, AP Bridge – WDS, Universal Repeater.
  • Скорость передачи данных:
    802.11g: 6, 9, 12, 18, 24, 36, 48, 54 Мбит/с
    802.11b: 1, 2, 5.5, 11 Мбит/с
  • Чувствительность приемника: до -100dBm
  • Выходная мощность передатчика: 20dBm
  • Безопасность: WEP, WPA/WPA2, фильтрация МАС-адресов, SSID broadcast disable.
  • Дополнительные возможности: IAPP, встроенный Radius-сервер.

DAP-1160 с прошивкой AProuter http://aprouter.com.br превратилась в довольно серьезное устройство с широким функционалом, включающим в себя массу полезных возможностей, от контроля качества WDS- соединений википедия до многофункционального шейпера википедия.

рисунок 2

Рис. 2. Точка доступа DAP-1160

Основные характеристики DAP-1160 с прошивкой AProuter:

  • Стандарты: 802.11b/g, 802.3/802.3u 10Base- T/100Base-TX Ethernet, ANSI/IEEE 802.3 NWay auto-negotiation.
  • Интерфейсы: 802.11b/g беспроводная LAN, 2 порта 10/100Base-TX Ethernet LAN
  • Диапазон частот: 2.4 – 2.4835 ГГц
  • Количество каналов: 13 (ETSI)
  • Схемы модуляции:
    802.11b: DQPSK, DBPSK, DSSS, CCK
    802.11g: BPSK, QPSK, 16QAM, 64QAM, OFDM
  • Режимы работы роутера: WISP Client, Bridge, Gateway, Router (WAN Ethernet), Router (WAN Wireless).
  • Режимы работы Wireless: Wireless Client, AP, WDS+AP, WDS-Bridge.
  • Скорость передачи данных:
    802.11g: 6, 9, 12, 18, 24, 36, 48, 54 Мбит/с
    802.11b: 1, 2, 5.5, 11 Мбит/с
  • Чувствительность приемника: до -100dBm
  • Выходная мощность передатчика: 20dBm
  • Безопасность: WEP, WPA/WPA2, фильтрация МАС-адресов, SSID broadcast disable.
  • Дополнительные возможности: IP Aliases, IAPP, Block Relay, Firewall, Traffic Control (шейпер), DDNS, Watchdog.

Антенны ANT24-0700C производства D-Link были выбраны по наилучшему показателю цена/качество в своем классе и из-за небольших размеров:

рисунок 3

Рис. 3. Антенна ANT24-0700C

Основные характеристики ANT24-0700C:

  • Диапазон частот: 2,4-2,5ГГц
  • Сопротивление: 50 Ом
  • VSWR: 1.92 (макс.)
  • Максимальное усиление: 7dBi
  • Допустимая мощность: 1 Вт
  • Диаграмма направленности в вертикальной плоскости (Вектор Е): 24 градуса.
  • Диаграмма направленности в горизонтальной плоскости (Вектор Н): 360 градусов.
  • Разъем: Reverse SMA «мама» (встроенный в антенну), переходник с RP-SMA на RP-TNC (внешний).
  • Материал корпуса: ABS, ABS+PC
  • Рабочая температура: От -20 до 65 градусов.

Построение сети

После завершения тестирования мы приступили к созданию собственно сети. В качестве базовой была выбрана классическая топология «звезда», центральной точкой которой стала DAP-1160 в режиме Bridge WDS, а «лучами» DAP-1150 в режиме WDS + AP. Использование технологии WDS позволяет получить на каждой точке доступа скорость передачи данных на уровне 1.2-1.4 Мбайт/с, максимальная скорость у клиентов составляет порядка 550-600 кБайт/с. Реальная скорость передачи данных зависит от типа клиентского оборудования и качества беспроводного соединения клиент-ТД, а также от количества клиентов и общей загрузки сети.


рисунок 4

Рис. 4. Общая схема сегмента сети

Покрытие каждой ТД составляет (в радиусе, значения указаны при наличии прямой видимости или незначительных препятствий, например деревьев):

  • Мобильные устройства (смартфоны, КПК, PSP и т.п.) – до 200м
  • Ноутбуки, нетбуки, USB-устройства со встроенными антеннами – до 300м
  • Ноутбуки, USB-устройства с внешними (или внутренними дипольными) антеннами – до 1500м
  • ТД в режиме клиента с направленными антеннами – до 10км

Установка точек доступа

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

Все наши хотспоты стоят на мачтах высотой 4-6 метров, которые расположены на крышах зданий высотой в 5-6 этажей. Рядом есть небольшой массив из 9-этажных зданий, но нам не удалось договориться с местным ОСМД*.

Питание на точки подается по витой паре, обычно из квартир наших клиентов (чтобы избежать бюрократии с ЖЕКами и ОСМД), по этому же кабелю клиенты входят в сеть. Взаимовыгодное сотрудничество: мы получаем место для установки и запитки точки, а клиенты получают VIP-доступ к сети :)

* Комментарий автора. Объединение совладельцев многоквартирного дома (ОСМД). Юридическое лицо, созданное владельцами для содействия использованию их собственного имущества и управления, содержания и использования неделимого и общего имущества.

Качество

На следующем скриншоте показаны характеристики соединения с ТД на расстоянии ~1000 метров при прямой видимости (см. рисунок 5):

рисунок 5.1
рисунок 5.2

Рис. 5. Качественные характеристики соединения в Atheros Client Utility

ТД: DAP-1150, мощность 20dBm, антенна штыревая 7dBi. Клиент: ноутбук Asus X51RL, WiFi-плата Atheros AR2425, антенна встроенная дипольная 4dBi.

Линк стабильный, текущая скорость линка «гуляет» в пределах 18-36 Мбит/с, это нормально. Скорость загрузки файла с сервера сети держится в пределах 400-500 Кбайт/с. Может показаться, что при средней скорости линка в 24 мегабита это немного, но нужно учитывать особенности технологии Wi-Fi, в которой мегабиты совсем другие, чем в кабельных сетях. Кроме того, режим WDS также вносит свои коррективы, и не в большую сторону. Если вы ожидаете от Wi-Fi волоконно-оптических скоростей, то вам действительно лучше посмотреть в сторону оптики. А Wi-Fi это простая, недорогая, удобная и достаточно качественная связь для всех.

Как это ни странно, но на качество связи почти не влияют погодные условия. Если линк стабилен в хорошую погоду, то он таким и останется в дождь, снег или туман. Возможно, немного снизится скорость, но связь будет. Наш опыт практической эксплуатации показывает следующие результаты: в дождь (даже сильный) или снег уровень сигнала между ТД снижается в среднем всего на 1-4 dBm, туман никакого заметного влияния вообще не оказывает. Замечу, что все точки стоят на примерно одинаковом расстоянии от центральной, которое составляет 800-1200 метров. Для Wi-Fi при прямой видимости это расстояние несерьезное. Так что мнение о влиянии погоды на Wi-Fi сильно преувеличено. Влияние погодных условий становится заметным только на больших расстояниях, от 5 км и более. А вот что действительно отрицательно влияет**: преграды, помехи в эфире, избыточная мощность радиоустройств. Данные факторы обсуждались и не раз, например на http://www.lan23.ru, поэтому подробно мы их здесь рассматривать не будем.

** Комментарий автора. В последнее время технология Wi-Fi в наших краях сделала явный рывок, но непонятно, вперед, назад или «налево». В эфире полный бардак, огромное количество различных устройств, большинство из которых настроены как попало или вообще не настроены. Все это снижает качество связи, а если так и будет продолжаться дальше – связь вообще станет невозможной… Вот какая картина открывается с некоторых наших хотспотов:

рисунок 6

Каждая ТД нормально выдерживает до 20 одновременно работающих клиентов, если нет «тяжелого» трафика, в первую очередь P2P. Если есть, то даже один клиент в состоянии через минуту сделать для всех остальных вход в сеть недоступным, а минуты через 3-5 отправить точку на перезагрузку. ТД почти не критичны к скорости или общему объему трафика, но очень критичны к количеству подключений. Это не значит, что использовать «тяжелый» трафик невозможно. Вполне возможно, если предпринять определенные меры для защиты сети от перегрузок. К таким методам защиты, например, относятся ограничение количества подключений на хост, работа по VPN, а также использование адаптивных шейперов и QoS. Но об этом поговорим в другой раз, так как это более относится к серверным технологиям, а не к Wi- Fi.

Несколько слов о клиентских устройствах

Сейчас на рынке представлена масса самых разнообразных устройств 802.11b/g/n. Из них довольно трудно, но возможно выбрать оптимальный*** вариант. Некоторые устройства, например USB-брелки со встроенной антенной, рассчитаны на работу только внутри помещения и обладают очень ограниченным радиусом действия. Даже одна стена или дерево под окном, для них уже неодолимая преграда.

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

При покупке ноутбука, КПК или любого другого устройства, оснащенного встроенным Wi-Fi, также обязательно интересуйтесь характеристиками Wi- Fi платы, типом и характеристиками встроенной антенны. Зачастую, встроенные платы подходят только для связи внутри комнаты или на расстояниях до 100 метров на открытой местности. Хотя есть и большое количество устройств, оснащенных качественным Wi-Fi и вполне способных поддерживать связь на приличных расстояниях.

Основные характеристики Wi-Fi устройств

  1. Стандарты, поддерживаемые устройством. От этого зависит универсальность и максимальная скорость передачи данных. В настоящее время в Европе поддерживаются следующие стандарты:
    • 802.11b (максимальная скорость 11 Мбит/с)
    • 802.11g (максимальная скорость 54 Мбит/с)
    • 802.11n (максимальная скорость 150/300 Мбит/с)
  2. Мощность передатчика и чувствительность приемника. Не стоит чрезмерно увлекаться мощностью, слишком мощный сигнал в городских условиях скорее вреден, так как вызывает многократные отражения и наложения, а также создает массу помех. Да и для здоровья он не очень полезен. На наш взгляд оптимальные значения составляют до 100 мВт (20 dBm) мощности и -95 dBm чувствительности.
  3. Возможность подключения внешней антенны и характеристики штатной. «Главная часть любого радиоустройства – антенна», это вам скажет любой специалист по любому виду радиосвязи. К Wi-Fi это тоже относится в полной мере. Для нормальной работы (приличной дальности и скорости) любого Wi-Fi-устройства необходима антенна с коэффициентом усиления не менее 4dBi.
  4. Функционал устройства. К этому относится все, что устройство умеет делать и насколько удобно его использовать. По этому критерию выбор огромный, от самых простых до сложнейших устройств, которые «умнее» вашего компьютера. Главное – достаточно четко представлять, чего вы хотите и сколько вы согласны за это заплатить.

*** Комментарий редакции. Многие задаются вопросом: «Как увеличить дальность связи?». Перво-наперво, при выборе WLAN-аппарата, обратите внимание на то, чтобы выходная мощность была как можно ближе к разрешенной 20 dB. Следующим решающим фактором является чувствительность. У лучших современых аппаратов она находится на уровне -97 dB. Чем выше чувствительность к слабым сигналам, тем выше дальность. Но это палка о двух концах, так как мы не учитываем при этом помеховую обстановку вокруг.

Как влияют эти величины на дальность связи? К примеру, аппарат с мощностью в 20 dB сможет обеспечить в два раза большую дальность приема по сравнению с 14 dB, т.е. разница в 6 dB дает двойной выигрыш. Если к этому прибавить, что аппарат с чувствительностью -97 dB, позволяет получить выигрыш в 4 раза по сравнению с аппаратом, у которого чувствительность равна -76 dB, то общий выигрыш будет 8-ми кратным.

Заключение

Это основные характеристики, но существует еще масса различных тонкостей, специфических моментов и технических особенностей. Рассказать здесь обо всех нереально, поэтому выбор оборудования – совсем непростое дело, в котором не помешает консультация специалиста. Если вы, конечно, сами не являетесь таковым :)

Продолжение следует…

Ресурсы

Статья из пятого выпуска журнала “ПРОграммист”.
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.

Обсудить на форуме – Беспроводная сеть масштаба микрорайона. Часть 1

21st
Авг

Полупрозрачность в Delphi

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

Перво наперво, качаем gdiplus.dll (если есть желание) с MS Official Site

Потом смотрим мои (DIB) и не мои (GdiPlus) модули в аттаче.

И так… Подготовим плацдарм для нашего окошка

код:

implementation

const
   WndClassName = ‘Trulyalya’;

var
   WndClass: TWndClass = (
     style: CS_DBLCLKS;
     cbClsExtra: 0;
     cbWndExtra: 0;
     hbrBackground: 0;
     lpszMenuName: NIL;
     lpszClassName: WndClassName;
   );

initialization
   WndClass.lpfnWndProc := @DefWindowProc; // I hope…
   WndClass.hInstance := HInstance;
   WndClass.hIcon := LoadIcon(HInstance, ‘MAINICON’);
   WndClass.hCursor := LoadCursor(0, IDC_ARROW);
   Windows.RegisterClass(WndClass);

finalization
   Windows.UnregisterClass(WndClassName, HInstance);

И так у нас есть зарегиный класс, вот ведь счастье ну мы не собираемся на этом останавливаться и пойдем до конца! Теперь давайте создадим окошко

Код:
hWnd := CreateWindowEx(WS_EX_TOOLWINDOW or WS_EX_LAYERED,
   WndClass.lpszClassName, NIL, WS_POPUP or WS_VISIBLE, 0, 0, 0, 0, 0, 0, HInstance, NIL);

Думаю то что здесь, понять не составит труда. Теперь стоит понять, что у нас есть окошко со стилем WS_EX_LAYERED и это дает нам по сути установить и отобразить любое 32х битное изображение разумеется в формате ARGB никакие PNG и т.п. на прямую не ставятся. Как же это сделать?

Код:

var
   Context: GpGraphics;
   Tmp: TDIB;
   Image: TDIB;
   Rect: TRect;
begin
   // Rect := GetWindowRect(); / GetClientRect(); не помню как точно, сами разберетесь

   Tmp := TDIB.Create(Rect.right – Rect.left, Rect.bottom – Rect.top); // создаем битмап по размеру окна
   Image := TDIB.Create(’my_image.png’); // загрузим какое то изображение

   GdipCreateFromHDC(Tmp.DC, Context); // создадим контекст GDI+ c Tmp
   GdipSetSmoothingMode(Context, SmoothingModeAntiAlias); // antialias включим
   GdipSetCompositingMode(Context, CompositingModeSourceCopy); // рисование с перекрытием
   GdipSetInterpolationMode(Context, InterpolationModeHighQualityBicubic); // качественно масштабировать изображения

   GdipDrawImageRectRect(Context, Image.Bitmap,
      0, 0, Tmp.Width, Tmp.Height, // покрываем все окно
      0, 0, Image.Width, Image.Height, // берем все изображение
      UnitPixel, NIL, NIL, NIL);

   GdipDeleteGraphics(Context);
   Image.Free();

И так, мы узнали размер окна, создали битпам для окна, загрузили картинку, связали GDI+ с Tmp и нарисовали с помощью GDI+ нашу картинку, потом все освободили. Теперь у нас есть Tmp на с отрисованной картинкой. Осталось дело за малым, отобразить на окне.

Код:

var
   BlendFunc: TBlendFunction;
   ZPoint: TPoint;
   LeftTop: TPoint;
   Size: TSize;
   Rect: TRect;
begin
   with BlendFunc do
   begin
      BlendOp := AC_SRC_OVER;
      BlendFlags := 0;
      AlphaFormat := AC_SRC_ALPHA;
      SourceConstantAlpha := 255; // не желательно менять это, да станет прозрачней, но тормаза начнутся, лучше перерисовать сам битмап в более прозрачный.
   end;

   // Rect := GetWindowRect(); / GetClientRect(); не помню как точно, сами разберетесь

   ZPoint := Point(0, 0);
   LeftTop := Point(Rect.left, Rect.top);
   Size.cx := Rect.right – Rect.left;
   Size.cy := Rect.bottom – Rect.top;

   UpdateLayeredWindow(hWnd, 0, @LeftTop, @Size, Tmp.DC, @ZPoint, 0, @BlendFunc, ULW_ALPHA);

Разумеется, не забудьте сделать это Tmp.Free();

Опять такие, это мануалчик, проверять не могу сейчас, да и думаю тут суть ясна, садитесь и пробуйте.
DIB.rar

Тема на форуме

Обсудить на форуме – Полупрозрачность в Delphi

20th
Авг

Основы неврологии

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

ОСНОВЫ НЕВРОЛОГИИ

by Utkin www.programmersforum.ru

«Настоящий программист должен:

Пройти все уровни Тетриса, пользоваться только своим бубном и написать нейронную сеть»

/ Махабхарата, эпос народов Индии

Нейронные сети – это математические модели биологических нейронных сетей, выраженные как программным, так и аппаратным способами. Поэтому, сначала рассмотрим единицы, из которых состоит биологическая нейронная сеть – нейроны. Нейроны – это специальные биологические клетки, объединенные в нервную систему организма. Это нужно для осуществления нервной деятельности, а именно принятие информации об окружающем мире (и внутреннем состоянии организма), выработка решений и управление исполнительными органами. Нейроны бывают нескольких видов, но мы рассмотрим только один, который для простоты восприятия классифицируем как классический вид нейронов, т.е. тех, что в основном используются в компьютерных моделях. Итак, нейрон представляет собой клетку, имеющую несколько отростков, один из которых является выводом нейрона, а остальные являются его входами. Вывод нейрона называется аксоном, входы – дендритами, а точка соединения аксонов и дендритов называется синапс. Нейроны по своей сути схожи с микропроцессорами (или ядрами процессора) и фактически занимаются обработкой информации, поступающей на их дендриты и выдающие результат на аксон. Практически нейроны работают с электрическими импульсами (только на основе ионов – прямая передача электронов в жидких системах не очень удачная вещь, приводящая обычно к разрушению жидкости либо емкости, в которой данная жидкость находится). Ничего не напоминает? Иными словами, нервная система подавляющего большинства организмов – есть огромная электрическая схема. Один нейрон может соединяться с несколькими тысячами других, что дает высокий параллелизм (именно параллелизм, а не модную многопоточность). Некоторые принципы работы нейронов не установлены (потому что нейроны-то у всех есть, а вот электронный микроскоп не у каждого), однако известно, что существует класс нейронов, использующий две группы входов – возбуждающие и тормозящий. Сигналы на возбуждающих входах заставляют нейрон генерировать сигнал на аксоне, тормозящие соответственно подавляют выходной сигнал. Дендриты имеют порог срабатывания, то есть требуют, чтобы на их вход поступал сигнал определенного уровня, иначе он будет не засчитан, И который может изменяться под воздействием ряда факторов – например попадания определенных веществ, таких как гормоны. Время срабатывания нейронов относительно небольшое: 2-5 мс, Однако более 6 миллиардов нейронных сетей доказали, что с их помощью можно решать довольно-таки сложные задачи, такие как: разум, научно-технический прогресс и создание цивилизаций (наравне с такими задачами как разрушение природы и конкурентных видов, а также активная и очень эффективная внутривидовая борьба). Более того, миллионы лет эволюции убедительно доказывают, что такого быстродействия вполне достаточно для решения задач реального времени. Компьютерные же модели пока, что ушли не так далеко и используются в научных целях (в основном для того, чтобы понять каким же образом 6-ти миллиардам нейронных сетей вообще удалось выработать такую концепцию как нейронные сети).

Анамнез

Несмотря на громкие заявления, реальное использование нейронных сетей на практике ничтожно в сравнении с традиционными алгоритмами. Основная причина – неточное формулирование задач, результаты которых также не очевидны – такие как прогнозирование погоды, биржевые сводки, в общем, все, что сводится к гаданию на кофейной гуще и где нельзя однозначно поймать за руку. Наиболее серьезным является применение нейронных сетей для распознавания образов на базе персептронов (сети, где нейроны сгруппированы в слои), что не удивительно, теоретические предпосылки данных концепций (и персептронов и распознавания образов и распознавания образов на персептронах) были разработаны 60-70-х годах прошлого столетия, примерно в тоже время, когда был создан автомат для автоматического распознавания индексов на почтовых конвертах. В последнее время мощностей обычных компьютеров вполне достаточно для создания полноценных нейронных сетей (чем мы собственно и будем заниматься), что позволяет все чаще применять их на практике (например, интересной темой является использование нейронных сетей для сжатия информации). Следует сразу же предупредить: использование нейронных сетей в задачах, алгоритмы которых легко перенести на языки программирования, в подавляющем большинстве случаев не эффективно (обычно по быстродействию).

Настольная инструкция по приготовлению нейронных сетей

Прежде чем писать программу, имитирующую биологические нейроны, нужно выработать модель. Я предлагаю следующую модель нейрона

Каждый нейрон имеет 32 входа, из них 16 положительных (считаю, использование термина возбуждающие выходы, здесь использовать не стоит) и 16 отрицательных. Выход соответственно один. Сразу договоримся о терминах – входы будем называть дендритами. Хотя в некоторых литературных источниках используется обозначение синапса, это на самом деле не совсем верно (почему написано выше). Выход также будем называть аксоном. Входы получают сигналы по принципу: есть сигнал / нет сигнала (0/1 или ложь/истина). Сам нейрон будет работать по принципу сумматора – он складывает все сигналы на каждой из групп входов. Соответственно, если число сигналов на положительных входах больше, чем на отрицательных, то нейрон устанавливает сигнал на выходе (аксоне). В обратном случае сигнал с выхода снимается (даже если сумма сигналов на положительных входах равна сумме сигналов на отрицательных).

Для данных нейронов порог срабатывания дендритов будет всегда и для всех одинаковым и равным уровню выходного сигнала. То есть наш нейрон будет работать с логическими величинами, и фактически будет являться предикатом (функцией возвращающей результат логического типа). Здесь по законам жанра научно-популярных статей следует погрузиться в обилие формул и не только математических. Но, как правило, для большинства читателей таких статей они абсолютно бесполезны, поэтому мы приводить их здесь не будем (кому интересно, найдет в прилагаемых источниках).

Почему 32 входа? Это компромисс между производительностью сети и быстродействием компьютера. Зависимость здесь следующая – чем больше выходов имеет нейроны, тем больше вычислительная мощность сети и тем больше вычислительных ресурсов требуется на реализацию.

Сам по себе нейрон устройство узкоспециализированное и его использование не в сети (даже если она и состоит из одного нейрона) является весьма проблематичным занятием, и поэтому далее мы рассмотрим модель нейронной сети.

Итак, помимо самих нейронов, сеть может содержать таблицу входных данных и таблицу выходных данных. Таблица входных данных характеризует информацию, поступающую в нейронную сеть – в биологии ее прототипом являются рецепторы. То есть датчики, с которых берется информация о задаче. Нейроны подключаются входами к таблице входных данных (заодно и к выходам нейронов) и формируют результаты, часть из которых помещаются в таблицу выходных данных. Данные, помещенные в таблицу выходных данных, символизируют решение поставленной задачи. Существует множество вариантов нейронной сети, но наиболее распространены персептроны – нейронные сети, где нейроны объединены в группы (слои). Обычно нейроны одного слоя могут соединяться с выходами нейронов другого, конкретного слоя, но бывают и исключения. В нашем варианте мы будем использовать хаотичное соединение нейронов (здесь имеется ввиду, что если порядок соединения нейронов и существует, то на данный момент он неизвестен), каждый нейрон имеет право быть соединенным с любым объектом нейронной сети, включая и таблицу входных данных, и таблицу выходных данных. Потому что это ближе к реальной биологической модели и строгих доказательств того, что нейроны объединены в группы или слои не обнаружено. Зато обнаружены нейроны – цель которых только передача импульса от входа к выходу, то есть это удлинители, которые соединяют между собой нейроны (те, что не могут быть соединены между собой напрямую ввиду их расположения).

Серьезным недостатком решения задач на нейронных сетях является отсутствие четких условий решения при постановке задачи перед нейронной сетью. Иными словами нельзя точно сказать, сколько нейронов требуется для решения данной задачи или достаточно ли данного числа нейронов для получения положительных результатов. Возможно, при определении конфигурации нейронной сети будет выбрано недостаточной число нейронов и решение задачи никогда не наступит. Существует ряд работ направленных на решение этой проблемы [1-5], однако до успешных результатов пока далеко (опять-таки, несмотря на заверения академиков и обилие формул). Сейчас выбор параметров в основном определяется на основании предыдущих опытов, либо экспериментальным путем. Я же выбрал хаотичную модель по двум причинам. Во-первых, персептроны не способны решать некоторые задачи независимо от числа нейронов в них (это было известно еще в Советском Союзе), а во-вторых, персептроны есть ограниченное подмножество моделей с хаотичным образованием нейронов и при изменении связей можно добиться получения персептрона практически любого типа. А возможность замыкания отдельных входов нейрона на его же выход или на константные сигналы позволяет имитировать дискретные уровни порога срабатывания.

Важной способностью нейронной сети – является возможность ее обучения за счет изменения порогов срабатывания и/или переключения связей между нейронами. Поскольку в нашем случае нейроны имеют одинаковые пороги срабатывания на всех входах и выходах, то обучение нашей модели будет происходить через изменение связей между нейронами. Кстати, на изменениях порога срабатывания есть алгоритмы автоматического обучения нейронных сетей, но опять же все это дело весьма и весьма условно. Потому что обучение возможно также только для некоторых видов задач и потому что такое обучение вырождается в генетический алгоритм, а это уже другая история, хоть и смежная (естественно исследователи не ищут легких путей). Обучение нейронных сетей такого типа производится случайным изменением связей между нейронами (как правило). Происходит это следующим образом. Пусть имеется некоторая задача, заключающаяся в решении некоторой функции f(x). То есть на каждое состояние таблицы входных данных должно быть только одно состояние таблицы выходных данных. Возьмем избитый пример – распознавание образов. Здесь на каждую картинку имеется соответствующая цепочка сигналов. Имеющейся сети дается тестовое задание – серия образов, затем сеть прореживается и получившаяся серия результатов сравнивается с эталонными данными. Если сеть отвечает требованиям задачи, то ее уже можно использовать (чего с первого раза на практике не бывает). Если же нет, то текущая конфигурация запоминается и на ее основе формируется новая сеть путем случайного изменения связи случайного дендрита случайного нейрона. Процесс распознавания повторяется. Теперь уже сравниваются оба результата тестирования: первоначальный и новый, полученный в результате мутации (здесь много биологических терминов). Например, сравнивать можно по проценту правильных результатов в серии распознавания образов. Теперь за основу берется та сеть, в которой процент совпадений больше и процесс повторяется до тех пор, пока результат тестирования не даст полного совпадения с эталоном. Или заранее определенное количество раз, иначе есть вероятность бесконечного процесса обучения. Здесь же нужно сразу определиться какой вариант сети лучше, в случае если оба варианта дают одинаковый процент узнаваний (новый вариант сети предпочтительней).

Подводные камни и течения

А что вообще может решать нейронная сеть? Теоретически даже может решить теорему Ферма. Для этого требуется не так уж много – нейронная сеть с числом нейронов примерно 1012 – 1015 степени, нейроны должны иметь возможность соединяться с несколькими тысячами других (порядка 20000). Если еще не понятно, то это мозг человека – лучшая иллюстрация работы нейронных сетей. На самом деле нейронов требуется еще меньше, потому что значительная их часть требуется на обслуживание и управление полуавтоматическими системами, таких как легкие, мышцы, желудок, саморегуляция и т.д. А также на передачу данных для других групп нейронов в те же самые органы. Плюс обработка огромного количества датчиков. Такую нейронную систему можно считать эталонной, но не идеальной. На ее обучение требуются годы.

На самом деле нейрон очень мощная логическая единица. С помощью нее можно эмулировать, например такие элементы как логическое «И», логическое «ИЛИ» и логическое «НЕ», то есть практически все современные логические операции легко могут быть выражены через нейронные сети. Одной из причин сложности конструирования эффективных сетей является тот факт, что логика на нейронах на порядок мощней обычной логики и всех ее смежных дисциплин, потому-то и выразить ее в рамках стандартной довольно-таки проблемно без привлечения интегралов и прочих трехэтажных формул (включая и логических). Далее с помощью нейронов можно эмулировать и работу сразу сложных блоков, таких как триггеры, счетчики, шифраторы, дешифраторы и т.д. И, наконец, нейронная сеть позволяет эмулировать аналоговые элементы (при наличии творческой жилки у программиста) и сложные схемы (на манер программ Qucs, Electronics Workbench, Microcap и т.д.).

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

Еще одна частая ошибка (наблюдается даже в серьезных трудах) – это временные интервалы функционирования нейрона относительно других в нейронной сети. Представим работу какого-либо нейрона. Итак, он прочитал данные и сформировал новое состояние аксона. В результате какой-либо другой нейрон будет читать уже новое состояние аксона, и работа всей системы в целом будет нарушена (потому как нейрон может обратиться к любому другому нейрону и не факт, что тот уже поменял свое состояние на новое). Проблема усугубляется тем, что новое значение на первом нейроне не всегда влияет на состояние последующих, а только для некоторых дендритов или некоторых состояний системы. Далее существует вероятность, что данный нейрон также изменит свое состояние и т.д. Таким образом, результаты работы могут быть полностью искажены. Отчасти благодаря такой проблеме персептроны и получили такое распространение. В них слои, нейроны и их взаимосвязи организованы в иерархии таким образом, что все нейроны всегда получают новые сигналы, то есть сначала первый слой берет данные из рецепторов, второй слой берет данные из первого слоя и т.д. Но нас это ни как не останавливает, решение этой проблемы снижает быстродействие, но зато позволяет имитировать нейронные сети любой конфигурации. Смысл заключается в кэширование результатов работы нейрона. Иными словами нейрон изменяет (или не изменяет) состояние аксона не сразу, а только после того, как абсолютно все нейроны в сети выполнят свою работу. Только после этого происходит изменение состояния всех нейронов. Это гарантирует, что все нейроны получат достоверные сигналы, и, следовательно, выработают достоверные результаты.

Далее следует правильно трактовать результаты работы. Для простых задач, решение которых однозначно описывается f(x), то есть один параметр и только одно результирующее значение для каждого значения входящего параметра, это самое результирующее значение перестает играть особую роль. Всегда можно написать транслятор результатов, с использованием стандартных средств программирования, в случае если их число не велико. Объясню на примере все того же распознавания образов. Допустим, перед сетью стоит задача распознавания образов букв A, B и С. Результатом должно быть 2 бита (см. таблицу 1 и 2):

Таблица 1. Вариации распознавания

Входной образ

Результат

Буква А

0

1

Буква В

1

0

Буква С

1

1

Любое другое изображение

0

0

На самом деле это все равно что, вот такая таблица (см. таблицу 2):

Таблица 2. Вариации распознавания

Входной образ

Результат

Буква А

0

1

Буква В

1

1

Буква С

1

0

Любое другое изображение

0

0

И нет особого смысла мучить сеть мутациями (особенно если она состоит из тысяч нейронов), гораздо быстрей и проще написать транслятор, который брал бы данные из таблицы выходных значений и выдавал требуемый результат (см. рисунок):

Таблица входных данных (рецепторы)

Нейроны

Таблица выходных данных

Транслятор результатов

Рис.1. Алгоритм продвижения данных

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

Продолжим с тем-же распознаванием образов. Требуя от сетей четкого и однозначного определения результатов, очень часто человек сам не в состоянии адекватно оценить предлагаемое изображение по ряду причин (это связано не только со зрением). В тоже время человек способен распознать образ даже очень плохого качества, основываясь:

а) на предыдущем опыте – что, как правило, недоступно для нейронных сетей. Иными словами, человек не только обучен узнавать образ, но он может и просто помнить его, что значительно упрощает идентификацию объекта. Нейросетям для запоминания же требуется несколько большее количество нейронов, чем у них есть.

б) на информации, которая недоступна нейронным сетям по условиям задачи. Самый простой пример – это разбор рукописного текста. Чтобы понять все слова совершенно необязательно понимать все буквы – этот эффект давно известен и в частности им пользуются американцы в повседневной речи. Они проглатывают окончания (иногда середину) слов, просто не договаривая их. Также и человек, распознав большинство членов предложения, в состоянии восстановить слово исходя из контекста, а не за счет определения символов слова.

Теперь представим, что у нас уже имеется нейронная сеть (в смысле компьютерная модель). Она способна решать задачи и вроде все отлично, но настоящего исследователя такая позиция нисколько не устраивает – как это работает? Может для решения задачи требуется меньше нейронов? Что будет если отключить вон тот нейрончик? Ведь чем меньше в сети нейронов, тем меньше ресурсов требуется для ее выполнения, а скорость выполнения – один из серьезных недостатков, сдерживающий развитие науки о нейронных сетях.

Заблокировать нейрон можно, если его заставить читать информацию из самого себя (и только из самого себя). Тогда на его аксоне будет пожизненный нуль (напомню, что в хаотичной модели нейронной сети любой нейрон имеет право адресоваться к любому источнику сигнала, включая и самого себя).

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

Как это ни странно, но к нейронным сетям можно применять и некоторые стандартные средства отладки. Один из них – контрольные точки. Можно получать данные с одного нейрона и писать их в массив для дальнейшего анализа. Какого? Самый примитивный пример – если нейрон не меняет своего значения на протяжении всей работы нейросети, независимо от входящих параметров, то следует задуматься над этим фактом. Может проще все дендриты, которые подключены к нему, переключить на константные значения в таблице входных значений? Фактически такой нейрон выполняет транспортную функцию – он передает константу (или формирует ее) для тех нейронов, которые подключены к нему. Это актуально для биологических нейронов (не может нейрон из мозга напрямую подключиться к нейрону из копчика), но бессмысленно для нашей сети – каждый нейрон имеет возможность напрямую подключаться к источникам сигнала. Более сложный анализ предусматривает сбор информации и ее сравнение с группой нейронов. Цель – поиск дубликатов, то есть устранение все тех же нейронов, выполняющих транспортную функцию.

Можно также поискать нейроны, выполняющие бесполезную работу. Это нейроны, к которым никто не обращается, то есть ни другие нейроны, ни таблица выходных данных. Соответственно и результаты их работы не нужны. Аналогично можно поступить и со значениями из таблицы входных значений: если к данному элементу никто не обращается, то возможно данный элемент просто не нужен, либо сеть работает неправильно и требуется расширенное тестирование. Задача всех оптимизаций такова, чтобы получить нейронную сеть без элементов, работа которых не влияет на результат работы нейронной сети: кто не работает, тот не должен есть ресурсы компьютера.

Препараты

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

Прежде всего, нам нужна модель нейрона, который будет являться центральным элементом нейронной сети. Итак, предлагаю следующую модель:

type

TNeron = class (TObject)

protected

Akson: Boolean; // Выход нейрона

Akson2: Boolean; // Кэш нейрона

Dendrits: Array [0..31] of Integer; // Входы нейрона (как адрес другого нейрона)

private

public

// Подготовка к работе нейрона

constructor Create;

destructor Destroy; override;

procedure Init(); // Инициализация нейрона

// Организация доступа

procedure SetDendrit(Num, Value: Integer); // Установка связи дендрита

procedure Update(); // Запись данных из кэша

procedure SetAkson2(Value: Boolean); // Запись значения в кэш

function GetAkson(): Boolean; // Чтение аксона

function GetDendrit(Num: Integer): Integer; // Чтение значения дендрита (связи)

end;

Akson – значение логического типа, это выход, откуда будут читаться результаты работы нейрона.

Akson2 – это кэш аксона, предназначен для синхронизации работы нейронной сети.

Dendrites – это массив ссылок на аксоны и другие элементы нейронной сети. Всего их 32 и на данном этапе нет различий между положительными и отрицательными входами (это делается программно). Ссылка представляет собой идентификатор объекта, в качестве которого может выступать:

а) нейрон;

б) элемент таблицы входных данных;

в) элемент таблицы выходных данных.

* Комментарий автора

Обратите внимание, идентификатор является общим для всех элементов (в том смысле, что, используя данный идентификатор, дендрит, может обратиться к любому объекту, включая и свой собственный аксон).

Вообще-то, в нейронной сети каждый тип элементов организован в свои собственные динамические массивы и имеет свой собственный индекс для доступа. Общий же (или абсолютный) идентификатор вычисляется для удобства использования и адресации в тех методах нейронной сети, где это непосредственно требуется. Собственно ничего сложного нет – нейрон, по сути, хранилище данных, не реализована даже функция работы нейрона. Просто потому, что его работа без нейронной сети невозможна. Все методы направлены в основном на чтение/запись полей класса. Вообще реализацию можно было сделать и без класса (даже проще), но потом это отразиться на удобстве дальнейшей модификации нейронной сети. Теперь рассмотрим модель нейронной сети:

type

TNNet=class

protected

// Поля

Data: Array of TNeron; // Нейроны

Count: Integer; // Количество нейронов

TableIn: Array of Boolean; // Рецепторы

CountIn: Integer; // Количество рецпеторов

TableOut: Array of Boolean; // Таблица результатов

TableOut2: Array of Integer; // Ссылки на существующие нейроны, откуда читать сигналы

CountOut: Integer; // Число сигналов в таблице результатов

private

function RunNeron(Neron: Integer): Boolean; // Выполнение указанного нейрона

procedure Updating(); // Перенос сигналов из кэша нейронов на их выходы

Procedure OutPuting(); // Берем все значения для таблицы выходных данных

public

procedure InitNerons(); // Инициализация набора нейрона

procedure InitTablein(); // Инициализация рецепторов

procedure InitTableOut(); // Инициализация таблицы выходных сигналов

constructor Create; overload; // Конструктор нейросети

constructor Create(InTable, Nerons, OutTable: Integer); overload; // Конструктор нейросети

destructor Destroy; override; // Деструктор нейросети

// Работа с рецепторами

procedure SetCountIn(Value: Integer); // Устанавливаем число рецепторов

procedure ClearTableIn(); // Устанавливает все рецепторы в False (гасит сигналы)

function GetCountIn(): Integer; // Возвращает число рецепторов

procedure SetElemIn(Num: Integer; Value: Boolean); // Устанавливает сигнал для указанного рецептора

procedure SetTableIn(Value: Array of Boolean); // Запись сигналов сразу для всех рецепторов

// Работа с таблицей выходных данных

Procedure SetCountOut(Value: Integer); // Устанавливает число элементов таблицы выходных данных

Function GetCountOut(): Integer; // Возвращает число элементов таблицы выходных данных (сигналов)

Function GetValueOut(Num: Integer): Boolean; // Чтение выходного сигнала

Function GetLinkOut(Num: Integer): Integer; // Читаем линк для данной ячейки таблицы выходного сигнала

Procedure SetLinkOut(Num, Value: Integer); // Установка линка на нейрон

Procedure ClearOut(); // Очистка таблицы выходных сигналов (установка в False)

// Работа с нейронами

Procedure SetDendrit(Neron, Num, Value: Integer); // Установка линка

Procedure SetDendrit2(Neron, Num, Value: Integer); // Установка линка (абсолютная адресация в рамках нейросети)

function GetDendrit(Neron, Num: Integer): Integer; // Чтение линка

Procedure Run(); // Выполнение одного шага нейросети

Procedure Run2(Tik: Integer); // Выполним указанное число циклов нейросети

Procedure Run3(); // Минимальный запуск

Procedure SetNeronCount(Value: Integer); // Задаем количсетво нейронов

Procedure Mutation(); // Мутация нейросети (произвольного входа произвольного нейрона)

Procedure Generator(InTable, Nerons, OutTable: Integer); // Формирование сети с заданным количеством нейронов и данных в таблице

end;

Как уже было отмечено ранее, все типы элементов нейросети сгруппированы в рамках своего типа в динамические массивы. Здесь только следует обратить внимание на TableOut2 – эта структура относится к таблице выходных данных и представляет собой ссылки на нейроны, откуда следует читать информацию в элементы таблицы. Все Count’ы в данном случае являются счетчиками числа элементов в массиве. В принципе, число элементов динамического массива можно узнать и в Дельфи, не пользуясь дополнительной переменной. Но наш пример учебный и предназначен для понимания принципов работы нейронной сети. Оптимизацию можно проводить уже после ознакомления с данным примером.

Итак, из полей класса нейронной сети видно, что он также не представляет собой ничего сложного. Теперь немного уделим внимание методам, это поможет понять логику их работы. Сначала рассмотрим методы в секции Private. Это методы для внутреннего пользования, то есть, они поддерживают работу класса, и не должны вызываться извне – это может нарушить нормальную работу нейронной сети.

Сразу возникает вопрос – почему RunNeron есть функция? Она возвращает True (истина), если нейрон может выполнить свою работу (и тогда он ее выполнит). Сделано так специально с расчетом на будущую модификацию сети. Например, в данном классе не реализовано сохранение и чтение нейронной сети во внешний файл. Представьте себе ситуацию, что Вы загрузили поврежденный файл или же во время работы изменили нейронную сеть. Тогда возможно нарушение ее внутренней структуре, что может привести к тому, что дендрит будет ссылаться на нейрон (или на элемент одной из таблицы), которого не существует в данной нейронной сети.

Updating должен выполняться (и выполняется) сразу после выполнения всех нейронов в сети – это процесс обновления сигналов на выходах нейронов. Она переносит значение из Akson2 в Akson в каждом нейроне нейронной сети. Функция RunNeron помещает результат работы нейрона именно в Akson2, что дает возможность другим нейронам получать старые данные и сохраняет целостность и корректность модели.

OutPuting – отвечает за сбор информации в таблицу выходных значений. После обработки всех нейронов осуществляется обновление их выходов (посредством Updating). Затем OutPuting читает информацию из объекта нейронной сети, руководствуясь информацией из TableOut2, и переносит результат в соответствующий элемент таблицы выходных данных.

Большинство остальных методов класса ориентированы на получение данных об объектах нейронной сети, а также на внесение в нее изменений, в том числе и внесение информации о задаче (информация в таблице входных данных). Пожалуй, интерес представляет только Run – выполнение нейронной сети. На самом деле это группа операций. А именно – выполнение всех нейронов, обновление состояний выходов нейронов и получение результатов в таблицу выходных данных.

** Комментарий автора.

Напоследок – не совсем удачное название класса выбрано специально, чтобы избежать возможного конфликта имен. Дело в том, что существует ряд классов и компонентов, имеющих в названии Net. Да и самописные инструменты, связанные с работой через сеть (не нейронную) обычно называются аналогично, а длинное имя элементарно лень писать. Все остальные вопросы можно уточнить в проекте, в котором реализована данная модель нейронной сети.

Заключение

В данной статье описана простая модель нейронной сети, при доработке которой можно добиться весьма неплохих результатов. Здесь-бы хотелось отразить те моменты, с помощью которых данный пример можно развить до вполне конкурентоспособного и, возможно, даже коммерческого варианта:

1. Сохранение и чтение нейронной сети в файл. В случае если Вы только отрабатываете свои навыки, то это может быть простенький текстовый формат по типу CSV (где все поля в строке разделяются символами табуляции). Простота устройства сети позволяет легко реализовать процедуру сохранения информации с использованием буфера, например, через список строк (такой как TStringList). Процесс чтения, как правило, немного сложнее из-за необходимости контроля целостности внутренней структуры сети.

2. Введение отладочных механизмов. Несмотря на то, что речь о них в статье шла, в примере они не реализованы. Здесь необходимо уделить внимание оптимизации алгоритма по скорости. Сложности возникать не должно, что и зачем в статье описано. Главное помнить, что работа сети есть большое количество итеративных (циклических) процессов, а на это требуется время, что может потребовать принудительного выделения ресурсов, например, с помощью Application.ProccessMessagess, либо аналогичных средств.

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

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

5. Написание дополнительных инструментов. В частности, можно написать генератор нейронных сетей, позволяющий создавать нейронные сети с некоторыми заданными характеристиками. Тогда проект может уже подгружать и работать с готовыми нейронными сетями.

6. Написать распределенную версию нейронной сети. Это позволит запускать ее на нескольких компьютерах и производить внутренний обмен посредством локальной и глобальной сети. Что в свою очередь дает решать более глобальные и ресурсоемкие задачи.

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

Источники. Что почитать

. Раздел википедии http://ru.wikipedia.org/wiki/Нейросети

. Введение в искусственные нейронные сети http://www.osp.ru/os/1997/04/179189/

. Нейронные сети http://www.statsoft.ru/home/textbook/modules/stneunet.html

. Введение в теорию нейронных сетей http://www.orc.ru/~stasson/neurox.html

. Материал по нейронным сетям http://www.artkis.ru/neural_network.php

. Нейронные сети – математический аппарат http://www.basegroup.ru/library/analysis/neural/math/

. Лекции по теории и приложениям искусственных нейронных сетей

http://alife.narod.ru/lectures/neural/Neu_ch12.htm

. Основные понятия Нейронных Сетей http://oasis.peterlink.ru/~dap/nneng/nnlinks/

. Нейронные сети: прогнозирование как задача распознавания образов

http://www.masters.donntu.edu.ua/2003/fvti/paukov/library/neurow.h

Статья из пятого выпуска журнала ПРОграммист.

Скачать этот номер можно по ссылке.

Ознакомиться со всеми номерами журнала.

Обсудить на форуме – Основы неврологии

20th

Регистры и смещение

ROD:

Смещение – это адрес в памяти, относительно точки отсчета. В данном случае точка отсчета не начало памяти, а адрес начала сегмента.

Эти извращенства были придуманы когда компьютеры были большими, а память маленькой. При таком раскладе команда занимает меньше места (адрес получается более коротким, а память-то совсем маленькая), для поддержки всего этого есть регистр, хранящий адрес начала сегмента, процессор сам заботится о том, что бы приплюсовать (или сделать конкатенацию, смотря как там устроено) смещение к базе, при работе с памятью.

GunSmoker:

Ну, сегментная модель памяти осталась в прошлом (и слава богу). В Win32 используется плоская модель памяти – это когда вся память представлена одним большим массивом из байт. Соответственно, многие из сегментных сегментов потеряли смысл и сегодня они эквивалентны (указывают на одну и ту же область памяти).

Очень грубо понять сегмент и смещение можно так: сегмент – это переменная типа массив 0..65535 из байт (к примеру). Смещение – это индекс в массиве. Чтобы обратиться к ячейке памяти (т.е. элементу массива) вам нужно взять адрес начала массива (сегмент) и прибавить к нему индекс (смещение). Т.е. когда вы говорите просто “индекс 15″ – вы не можете узнать, про какой байт идёт речь, пока вы не скажете от какого массива этот индекс. Иными словами, индекс имеет смысл, только будучи приписан к массиву (”индекс относителен к началу массива”). Аналогично и смещение задаёт сдвиг от начала сегмента.

Связано это с тем, что 16-ти разрядное число не может адресовать много памяти. Зато два числа (сегмент + смещение) дают большую свободу. Эта модель – не более, чем обходной путь. В 32-х разрядном мире смысла в этих изворотах нет.

Ну а параграф – это просто 16 байт.

Лучше всего это понять, рисуя на бумажке. Неужто в книге нет иллюстраций?

Вообще, эту информацию можете смело пропустить – я не думаю, кто она хоть как-то применима в мире Win32, если только вы не станете писать приложения под Windows 3.1.

P.S. Возможно, вам будет интересно.

Интересная тема на форуме, присоединится к обсуждению

20th

Маленькие помощники программиста

AllЕжедневно мы сталкиваемся с рутинной работой, которая отнимает львиную долю нашего времени. В этой статье я попробую «приучить» читателя к созданию маленьких помощников, оптимизирующих работу или сокращающих время рутинных операций…

Маленькие помощники программиста

Алексей Шишкин

by Alex Cones www.programmersforum.ru

http://www.programmersforum.ru/member.php?u=40711

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

Но, не смотря на такую жестокую реальность, программисты главным образом живут в мире виртуальном. Поэтому ничто не мешает им улучшать свою жизнь, создавая «роботов»-помощников. «Но какие-же помощники могут быть у программиста?» – скажете Вы. Я постараюсь ответить на Ваш вопрос, опираясь на собственный опыт.

История появления…

Итак, первая вещь, которая была создана мной для облегчения собственной жизни – это «Заполнялкин» (см. рисунок 1):

Рис. 1. Утилита «Заполнялкин»

Рис. 1. Утилита «Заполнялкин»

Эта программа предназначалась для того, чтобы оптимизировать написание больших блоков кода, отличающихся только ссылками. Так, например, введя шаблон:

Label@@.Caption := IntToStr(@@);

Можно было получить практически неограниченное количество следующих строк:

Label1 := IntToStr(1);

Label2 := IntToStr(2);

Label3 := IntToStr(3);

Label4 := IntToStr(4);

Label5 := IntToStr(5);

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

Второй программой стал Resource Builder (см. рисунок 2):

Рис. 2. Утилита Resource Builder

Рис. 2. Утилита Resource Builder

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

Итак, вопрос удобства создания программ уже не стоял, я приступил к улучшению окружающей меня обстановки: я создал G.A.P. Создать эту программу меня вдохновили действия Educated Fool – он создал excel-ский макрос, который упаковывал проект в архив, создавал к нему превью и отправлял на FTP сервер. По аналогии моя программа делает снимок экрана (или части его ― по выбору пользователя), дает возможность создать превью к снимку, отметить на нем что-то и отправить на сервис хранения картинок, оставив ссылку на картинку в буфере обмена (см. рисунок 3):

Рис. 3. Утилита G.A.P

Рис. 3. Утилита G.A.P

* Комментарий автора

На этом месте я хочу предупредить читателя о том, что данная статья задумывалась вовсе не как реклама этих программ, а как пособие начинающему «импруверу» (от англ. improve – улучшать). Не бойтесь экспериментировать, и запомните одну вещь – ЛЮБАЯ работа может быть оптимизирована. Даже если кажется, что это не так.

Однажды мне потребовалось залить на файлообменный сервис достаточно большой файл. С моей полу-диалапной скоростью эта задача имеет решение только посредством FTP доступа. К счастью сервис предоставляет такую услугу. Радости моей не было предела и на первую же ночь я поставил на загрузку злополучный файл. Проснувшись утром и просмотев логии, я ужаснулся – сервер отключает меня каждые 15 минут бездействия. Даже если в этот момент загружается файл. Выход был лишь один – отправлять команду просмотра каталогов каждые 10 минут (благо для этого была выделена отдельная кнопка). Но не кликать-же по ней каждые десять минут, пока файл не загрузится? Хотя-я… Собственно, почему нет? За 15 минут был создан Click Shot (программа, которая будет кликать за меня в нужную точку экрана через заданный промежуток времени)

Рис. 4. Утилита Click Shot

Рис. 4. Утилита Click Shot

Думаю, лишним будет говорить то, что файл был успешно загружен.

Вчера один из моих товарищей вставил в мой ноутбук свою флешку. Несмотря на то, что на ней были только документы, Windows спросила разрешения запускать с неё программы. Снизойдя до отказа, я включил отображения скрытых и системных файлов и обнаружил autorun и exe-шник. Открыв авторан, я понял, почему антивирус продолжал молчать

[AutoRun

;lsbvrkskjvbliurbsv

;srvlbsrvksrjksr

open = klbhk.exe

;kjbsjvbkvksjvn

Одна закрывающаяся скобка… И план вторжения армий провалился… Но что-то я отвлекся. Удаление файлов прокатывать не захотело по причине аттрибута «системный» у обоих файлов. Форматировать флешку мне не позволили, и я накатал программу, изменяющую аттрибуты каталогов и файлов по выбору пользователя. Так появился на свет A.ch (см. рисунок 5):

Рис. 5. Утилита A.ch

Рис. 5. Утилита A.ch

Заключение

В завершение статьи хочу отметить, что каждая решенная проблема приносит удовольствие, но лично для меня большее удовольствие приносит решение проблемы. Дерзайте, и да прибудут с вами маленнькие помощники программиста!

Ссылки

. Заполнялкин. Версия 1.0 http://www.programmersforum.ru/showpost.php?p=367784&postcount=26

. Resource Builder http://www.programmersforum.ru/showthread.php?t=69505

. GAP http://www.programmersforum.ru/showthread.php?t=69505

. Click Shot http://www.programmersforum.ru/showthread.php?t=92768

. A.ch – Attribute Changer http://www.programmersforum.ru/showthread.php?t=104574

Статья из пятого выпуска журнала ПРОграммист.
Скачать этот номер можно по ссылке.
Ознакомиться со всеми номерами журнала.

Обсудить на форуме – Маленькие помощники программиста

20th

Рассылка. Выпуск 72.

redaktor От ведущего.

Здравствуйте. Сегодня у нас очередной выпус рассылки от клуба программистов. Этот 72 выпуск посвящен пятому номеру журнала ПРОграммист. Мы его долго ждали и не зря. Некоторые заметки и статьи мы просмотрим в этой рассылке.

(читать всё…)

19th
Авг

Разработчики – интерфейс – пользователи

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

«Встречают по одежке, а провожают по уму»

Демьяненко Александр by Grenles http://www.programmersforum.ru/member.php?u=17572

GRENLES@yandex.ru

Часть первая. Философия

Надо же! Почти вступление! Не скажу, что я большой профессионал, особенно по теме данной статьи, но и не скажу, что я совсем уж любитель. Я учусь писать, читать, видеть, думать, и снова начинаю этот процесс сначала*.

* Комментарий автора.

Кто-то сказал: «хочешь что-то понять, – объясни это что-то другому, – он может и не понять

сказанного тобою, но уж ты сам точно это поймешь».

Очень сложно учить чему-то профессионалов, особенно в той области, которую они знают лучше тебя, гораздо проще – стать их учеником. Однако, как ни странно, порой именно любители пишут книги для профессионалов и учат их ремеслу и только лишь потому, что не всегда профессионалы умеют выразить доходчиво свои знаний для других. Поэтому не все так плохо, но и не так просто, как кажется на первый взгляд. В мире всегда полно тех, кто задает вопрос: «А с чего мне лучше начать?». Мало того, есть еще такие профессионалы, которые проснувшись утром, понимают, что они ничего не знают из того, что должны знать. Именно поэтому каждый день они начинают с поиска и изучения новых горизонтов знания. Каждый раз, узнав больше, они понимают, что все равно ничего не знают и снова начинают бесконечный процесс приобретения знаний. Вот для этих людей и не только для них я и начал разговор на заданную тему.

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

От того, насколько удачно продуман и реализован интерфейс продукта, зависит 75% успеха разработчика и 100% эффективности использования потребителем конечного продукта. Случается, что и начинающие разработчики, и гранды компьютерной индустрии, как студенты на экзаменах, «засыпаются» на плохо сделанном интерфейсе для своих великих проектов. К сожалению, не всегда с первого раза удается найти удобный способ взаимодействия пользователя и продукта. То, что ясно разработчику, не всегда очевидно пользователю и наоборот. Почти как мужчина и женщина всегда говорят на разных языках, так разработчик и пользователь живут и мыслят на основе разных категорий.

Садясь за статью и желая раскрыть тему полнее и правильнее, я решил обратиться в Интернет, чтобы узнать: «А как на мой вопрос отвечали другие?». Не скажу, что эта фраза мне попалась первой, но зацепился я за нее сразу: «Для ReGet дизайн придумывала студия Артемия Лебедева. В результате пользоваться ReGet, в отличие от FlashGet очень удобно. Можете в этом сами убедиться» [1]. При этом, я не думаю, что функционально обе программы сильно разнятся, выполняемые ими задачи практически одни и те же, но разница в том, что одну программу мы используем, а другую просто имеем ввиду, зная что она есть.

Самый веский аргумент, окончательно подтолкнувший меня на создании серии статей по заданной теме, я нашел в источнике [1]: «в России слишком много программистов-самоучек, которые все этапы создания программы от идеи программы до ее реализации выполняют сами». К сожалению, не у всех есть возможность нанять профессиональных дизайнеров или найти специалиста в этой области, поэтому приходится «изобретать велосипед» самому.

Начнем. С чего? Элементарно! What song? Книги!

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

1. Стив Круг. Веб-дизайн или не заставляйте меня думать

ВЕБ ДИЗАЙН

ее стоит прочесть хотя бы для того, чтобы понять основные принципы «юзабилити» и того, как не стоит делать интерфейс. Кто-то скажет, – но она же только для тех, кто создает веб-сайты, Отвечу, – а кто сказал, что создание интерфейса программы сильно отличается от создания интерфейса веб-сайтов? Я бы сказал иначе, создание веб-сайтов выросло из принципов создания программ, именно поэтому внешний вид может быть разным, но подходы, принципы, правила одни и те же. Но, как ни странно, думать надо в любом случае и при создании сайта, и при создании программы. Хорошо думать, когда есть знания. Замечательно думать, когда знания перешли в умения. Надеюсь, уважаемый читатель, ты меня понял.

2. Джеф Раскин. Интерфейс: новые направления в проектировании компьютерных систем

Джеф Раскин1

считаю весьма полезными для разработчиков, желающих стать профессионалами. Я бы не сказал, что по году создания и издания книга нова. В найденной мною версии она датируется 1996 годом, но только что это меняет? В книге весьма интересно разложены по полочкам элементы интерфейса их плюсы и минусы, и порой высказывается совершенно иной взгляд на привычные, казалось бы, вещи: отказ от GUI, отказ от использования мыши, отказ от разбиения задач по приложениям. В определенном смысле программы интернет-браузеры реализуют эту идею, когда в одном окне выполняется все – звук, графика, редактирование, просмотр видео и прочие действия.

3. Иоханнес Иттен. Искусство цвета

Иоханес Иттен

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

4. В.В. Головач. Дизайн пользовательского интерфейса

влад головач

Скажу сразу, она попалась мне на глаза гораздо позже других книг и понравилась намного больше тем, что в ней нет строгой теории, а сразу идет разбор конкретных ситуаций – ошибок и решений. Как ни странно, на фоне прочтения первых трех книг, эта – четвертая книга как будто подвела итоги решений, описанных теоретически в «умных» книгах.

Мало того, изложение материала таково, что я бросил чтение других книг и продолжил чтение только этой книги. При этом, на основании изложенных примеров, я реализовал несколько удобных «фишек» для своих программ на будущее, и они мне понравились. Советую прочесть эту книгу, просто потому, что это полезно и интересно.

Есть более новая версия этой книги – «Дизайн пользовательского интерфейса 2. Искусство мыть слона».

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

Что наша жизнь? И…

Классический ответ на заданный вопрос – «игра». В каком-то смысле, если задуматься, так и есть – вся наша жизнь есть одна сплошная игра. И в любой игре есть маски, костюмы, актеры, зрители. Я нашел этой игре новое обличие:

. зрители – это пользователи, потребители созданного вами продукта – программы, фильма, музыки, книги и тому подобного

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

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

Разрабатывая программу, мы играем роль самого Создателя. Может быть, именно поэтому большинству так нравится играть, многим – нравится программировать, а некоторым из числа избранных – создавать и творить. Все это теоретически хорошо, но возникает вопрос, а какой ты создатель? И для кого ты создаешь? Мучаешься, не спишь ночами, читаешь гору разной литературы, бьешься над парой строк кода и все ради чего? Чтобы однажды узнать – твой труд никому не нужен, потому что ты не смог найти удачный способ взаимодействия пользователя с твоим творением. Не смог донести до него свою мысль и идею – ответ на главный вопрос: «…зачем ему нужно то, что ты создал?». Тебе-бы встретиться с ним, поговорить по душам за рюмкой чаю, но уже поздно – время упущено и пользователь ушел к другому, так и не поняв, что же ты хотел для него сделать. К сожалению, в жизни часто так бывает, что разработчик и пользователь встречаются друг с другом тет-а-тет весьма и весьма не часто. Особенно последняя фраза касается начинающих разработчиков – опытные-то знают, что пользователя надо завлечь пряничком, блестящей оберткой, усадить на мягкий стульчик, подать вкусный чай… Часто начинающие разработчики не то чтобы забывают о пользователе, они порой плохо представляют, а кто это вообще такой.

Пройдемся по науке

Собственно, что я хотел сказать? Для начала надо немного определиться и ответить на вопрос главный вопрос статьи: «Что такое интерфейс***?»

** Интерфейс (от англ. interface — поверхность раздела, перегородка) — совокупность средств

и методов взаимодействия между элементами системы [4].

Ответ обобщенный, подходит для разных сторон и сфер человеческой деятельности, но в своей сути он отражает смысл этого явления. Далее, подумав немного, решил, что мир придуман не вчера и все процессы должны быть так или иначе давно регламентированы и описаны. Я начал искать стандарты, правила, ГОСТ-ы. Приводить здесь подробное описание этих документов абсолютно бессмысленно. Каждый сам может найти их в сети Интернет. Будет гораздо лучше, если выскажу свои соображения, которые сделал, переработав найденную информацию…

Большинство ГОСТ-ов, найденных мною, направлены на разработку технической документации, связанной с процессом разработки программного обеспечения. Создается впечатление, что изначально в 70-х начале 80-х годов прошлого столетия упор делался на техническую сторону этого вопроса – разработку и детализацию алгоритмов, средств сопряжения, подбор технической базы, создание различных инструкций по эксплуатации и прочее. Старый ГОСТ именно это и регламентировал. Впрочем, если подумать, так оно и должно было быть, так как программирование по сути родилось из математики и на первом месте было решение задач, а не внешнее оформление. Лишь в ГОСТ, относящимся к недавним советским временам, а именно, ГОСТ 19.201-78 и ГОСТ 24.207-80 можно неявно увидеть фразы, частично указывающие на средства взаимодействия с пользователем: «требования к программе или программному изделию», «требования к маркировке и упаковке». Правда, прочтя эти фразы, явно и не скажешь, что тут имеется ввиду «интерфейс». Тем не менее, в источнике [2] нашел следующее: «Техническое задание, как правило, разрабатывается на основе ГОСТа 19.201-78 «ЕСПД.

Техническое задание. Требования к содержанию и оформлению». Таким образом, получается, что разработчик должен сам знать и подразумевать, что в задание должны закладываться вопросы, связанные с интерфейсом. Явно это в ГОСТ не звучит. Но это было «тогда». По ГОСТ советских времен подразумевалось, что интерфейс у нас возникает сам собой, – это следует из текстов документов. Получалось, как в известной фразе: «В СССР секса нет, а дети есть». Всем известна фраза о том, что в мире все подвержено изменениям. Тоже самое можно утверждать и про ГОСТ-ы. Не прошло и 20-ти лет, изменились требования времени, реалии, изменилось само время. Согласно документам, датируемым 2000-м годом и выше, разработчики ГОСТ уже узнали про интерфейс и даже явно написали об этом в «Пример шаблона технического задания (ТЗ) на сайт» [3], где есть два раздела: «Требования к графическому дизайну сайта», и «Требования к дизайну сайта». Это уже радует. Конечно же, кажется совершенно очевидным, что сайт без дизайна не сайт. Однако, судя по всему, на осознание этого факта разработчикам ГОСТ потребовалось время. Думаю, что оно им еще будет нужно, чтобы создать отдельный ГОСТ, касающийся только дизайна, как такового.

В итоге, проглядев различные ГОСТ, документы, шаблоны и примеры, сделал основной вывод. Сейчас, как и раньше, основной упор идет на правильное, точное, детальное оформление документации по всем этапам разработки продукта – замысел, поиск информации для начала разработки, процесс разработки, тестирование, внедрение, эксплуатация. С одной стороны – это правильно, сложные продукты делает много людей и для удобства их работы и взаимодействия нужны документы, описывающие детально и правильно различные этапы процесса создания конечного продукта. А с другой стороны – это жуткая бюрократическая формальность, требующая от каждого участника процесса описывать каждое свое действие и решение. Именно поэтому создание документации так не любят разработчики. Порой время, требуемое на ее создание соизмеримо со временем создания самого программного продукта. Но, опять же, мы вернулись к тому, от чего пришли – в настоящее время по ГОСТ дизайн и интерфейс упирается в «бумагу».

Если внимательно подумать, то это правильно, заказчику «нечто» не покажешь, а нарисованное и написанное на бумаге вполне возможно. Поэтому, насколько мне представляется, знание ГОСТ и этапов от создания технического задания до сопровождения готового продукта необходимо не только крупным фирмам, но и одиночным разработчикам, так как это позволяет делать все правильно и приучает к определенному порядку. Конечно же, для написания программы, из разряда «калькулятор» вряд-ли нужно техническое задание, но знание этого необходимо. Прошлись по науке? Хотя ГОСТ и прочие нормативные документы необходимо знать, но, по сути, это скучно, сухо и сложно. Пожалуй, хватит – идем дальше.

Что вы делаете после того, как решили написать собственную программу?

Предполагаю, что 95% респондентов ответят – обдумываю идею программы, способы реализации, типы данных, выбор среды программирования и прочие детали и … будут почти правы. А почему – почти? А потому «почти», что мало-кто сразу из большинства разработчиков начинает думать над тем: а как будет выглядеть ваше будущее творение перед лицом пользователя. Удобно-ли пользователю будет работать с программой***. Согласен, что на первом этапе весьма сложно представить цельный интерфейс программы, так как и программы, собственно говоря, еще и нет, но задуматься над этим стоит уже с самого начала.

*** Комментарий автора.

Скажу, что два года назад, когда я стал активно заниматься программированием, а не просто сопровождением программ и написанием мелких макросов, я больше корпел над алгоритмами и достижением результата, – программа должна делать то, что хочет от нее пользователь. Интерфейс возникал или по ходу написания, или так, как было удобно мне, а не пользователю. После запуска продукта в эксплуатацию как минимум неделя была посвящена только тому, что я отвечал на вопросы что, где, почему и зачем. Теперь же я стараюсь думать не только над «внутренностями», но и над «внешним видом».

А как вы пишете программу?

Думаю, что большинство ответят примерно так: «Сажусь за компьютер, открываю среду программирования и начинаю писать код». Если это визуальная среда программирования, то обычно 100% действий начинается с того, что на пустую форму перетаскивается мышкой какой-либо элемент из палитры компонентов и… вот тут начинается самое интересное, вы ступаете на дорогу «войны». Я не ошибся, именно дорогу войны, даже точнее будет сказать – тропу. Почему? Все очень просто – весь процесс разработки есть борьба с самим собой, с кодом, ошибками и прочими неприятностями. В любой программе во время ее написания никогда с первого раза не бывает правильно размещенного элемента в нужном месте формы, соседние элементы иногда начинают мешать друг другу или просто не помещаются на форме так, как этого хочется. В итоге вы все время воюете – с алгоритмом, со средой разработки с внешним видом. Причем чаще всего страдает от всей этой «битвы» интерфейс. Да и кто серьезно задумывается**** над тем, насколько удобно пользователю будет работать с программой, когда на первое место выходят задачи логики функционирования программного продукта?

**** Комментарий автора.

Пример из моей практики. В связи с производственной необходимостью потребовалось решить проблему автоматизации учета. Проблема была в том, что «низы» уже не могли вести расчеты «вручную» в связи с их сложностью, объемом и цикличностью, а «верхи» не знали быстрого решения проблемы, то есть подходящего программного решения по цене и решаемым задачам не было. В итоге, по стечению различных обстоятельств, наш системный администратор взялся за разработку программы «с нуля». То, что для него это было тяжело, это мягко сказано, это было очень тяжело. Ему приходилось решать проблемы абсолютно разного рода – выполнять свою непосредственную работу, параллельно изучать новые методы и технологии программирования, изучать предметную область задачи, решать дела домашние, между этим делать еще что-то. Мало того, периодически он «воевал» с непосредственным начальством по поводу совмещения прямых рабочих обязанностей и работы по написанию программы (программу он писал добровольно и, в том числе, на своем рабочем месте, а какому начальству понравится такое?). Смысл всей этой предыстории таков, что ему было не до интерфейса и дизайна программы. Для него было важным решить технические проблемы стоявшей перед ним задачи. В итоге задачу он решил для своего уровня и того времени достойно. Однако, в процессе эксплуатации выяснилось, что где-то он не додумал логику, где-то проиграл в удобстве интерфейса. При этом каждый день он решал какие-либо проблемы, связанные с внедренной программой – дописывал, исправлял, модернизировал, консультировал пользователей, писал документацию. Добавление новых решений и отчетов в программу, привело к тому, что с каждым днем она становилась все функциональнее и сложнее. В итоге, несмотря на то, что он видел и знал огрехи интерфейса, переделать или исправить что-то было уже практически невозможно, так как это означало переписывание программного кода практически сначала.

Вывод, напрашивающийся из всей этой ситуации таков – в условиях нехватки времени (а в обычных «рабочих» условиях так и есть) одному человеку практически невозможно создать удобную во всех отношениях программу. Все усилия в этом случае направлены на то, чтобы найти и реализовать логическое решение, внедрить и запустить в работу программу. Понимание того, как все должно быть, как удобнее работать, приходит уже после того, когда программа запущена в работу и эксплуатируется. И, часто получается так, что реализация «удобства интерфейса» уходит на второй план, так как возникают более важные задачи, – исправление допущенных ошибок в логике, модернизация и прочее. Именно поэтому большинство серьезных фирм очень много времени тратят на подготовку процесса, создание «стартовой базы», и лишь потом начинают программировать. В экстремальных условиях интерфейс страдает всегда.

Когда вы задумываетесь о том, кто и как будет работать с вашей программой и какие ситуации могут при этом возникнуть?

А вот на эти вопросы я не могу дать однозначного для всех ответа. У каждого найдется свой ответ, но, в конечном итоге, правильный ответ на эти вопросы всегда звучат из уст пользователя. Почему из уст пользователя? Отвечу цитатой рецензента этой статьи, литературного редактора этого журнала, Utkin: «…даже в идеальной программе пользователи найдут что покритиковать. Просто потому что пользователи всегда придирчивы. Одним подавай одно, другим требуется прямо противоположное». Поспорить с этим сложно. Еще классик И.А. Крылов написал басню про Слона, который рисовал картину в угоду всем и в итоге никому его шедевр не понравился. В данном случае – тот же самый процесс.

Мало того, этот самый «пользователь» всегда найдет ту самую ошибку, которую никто из разработчиков даже в страшном сне не мог увидеть. При этом, сложно сказать, какая ошибка хуже – алгоритмическая или визуальная, обе одинаково неприятны. Разница лишь в том, что логическую ошибку среднестатистический пользователь не всегда можно найти, особенно, если плохо знает логику функционирования программы, – такую ошибку не всегда видно. С точки зрения пользователя, логические ошибки могут быть вообще никогда не обнаружены. По известной статистике большинство пользователей используют лишь 5-10% возможностей программы, про остальные 90-95% возможностей, где и может оказаться логическая ошибка, они могут не знать. Визуальная ошибка всегда хуже – она просто заметнее. Классический пример из недавнего прошлого – это ошибка вывода изображения видеокартой. Чаще всего такие ошибки выявлялись в играх, как более требовательным к ресурсам компьютера, а не «офисных» приложениях, которым хватало «гарантированного минимума». Они проявлялись в том, что могли «ломаться» контуры изображаемых предметов, возникали непредвиденные визуальные эффекты, искажения картинки в целом, в худшем варианте или просто ничего не было видно, или компьютер шел на перезагрузку. При этом, источник ошибки мог быть с любом месте – как в сбое видеокарты, так в используемом программном обеспечении (драйверах видеокарты, драйверах DirectX или OpenGL, несовместимости с операционной системой и прочее).

Для крупных корпораций уровня Microsoft или Adobe, когда есть рынок, бренд, сформированный круг пользователей, которые все равно не уйдут, такие ошибки менее ощутимы. Да, они неприятны, никто не говорит, что ошибки – это хорошо, но все-таки, менее ощутимы. Для таких корпораций они всего-лишь повод создания обновлений и выпуска новых версий программ. При этом, вовсе на факт, что старые версии работали хуже или не удовлетворяли потребностям пользователя. На мой взгляд, рассматривая, как пример, программу Adobe Photoshop, для большинства пользователей (не дизайнеров) вообще достаточно ее варианта в версии 9.0. Новые возможности программы, выпуск линейки продуктов от Adobe в виде нескольких DVD дисков, еще раз повторю, обычным пользователям, вообще не понятны и не нужны, – они просто не пользуются ими в полной мере. Хотя, как бренд и признак «статуса», большинство просто устанавливают эти продукты на свой компьютер, не зная и 5% всех возможностей. Грубо говоря, они микроскопом забивают гвозди, изменяя размеры фотографий или сохраняя их в другой формат.

Возвращаясь к теме разговора, еще раз скажу, что ошибки для крупных корпораций менее болезненны, чем для разработчиков-одиночек. И вот почему. Образно говоря, обслуживание ошибок у них поставлено на конвейер – службы поддержки, бесплатная горячая телефонная линия, консультации он-лайн и через различные сервисы в сети. В данном случае под «ошибками» я подразумеваю не только непосредственно ошибки в программе, найденные пользователями, но и «ошибки в мозгах пользователей», связанные с обычной человеческой ленью и нежеланием разобраться и думать. С одной стороны – такая ситуация везде и всюду и считается обычной, а с другой – это повод, способ, средство знать еще сильнее «привязывать» пользователей к себе. Если бы большинство из нас внимательно читали бы документацию и перед тем, как задать вопрос, подумали над его решением, то половина вопросов исчезла, а службам поддержки нечего было бы делать.

Если вы «один из подающих надежды», тот самый герой, призванный удивить мир, то у вас просто нет права на ошибку. Вы должны выстелить точно в цель, чтобы громко и красиво заявить о себе. В противном случае велика вероятность того, что пользователи вас не поймут и забудут навсегда ваш адрес и ваш продукт и, развернувшись, уйдут к другим. Исключение в этой ситуации, составляет всеми горячо любимый Билл Гейтс, который, несмотря на то, что первые версии его операционный системы Windows содержали много ошибок и пользователями по всему миру изначально вообще не воспринимались, смог продать свою систему этому миру. Возможно, одна из причин его успеха в том, что первыми пользователями его системы были студенты, ставившие над ней эксперименты. А так как чаще всего то, что изучается в университете, дальше используется в повседневной работе, то Windows и получила такое распространение. Впрочем, умалять заслуг Билл Гейтса, как удачного менеджера и торговца не стоит. Думаю что, еще одна хитрость, принесшая успех Windows состоит в том, что долгое время вообще никто даже и не знал, что надо покупать лицензии на эту систему. Она эксплуатировалась везде и всюду просто так, благодаря умным ребятам, называющих себя хакерами. В свое время ходила шутка о том, что самая лицензионная часть операционной системы – драйвер от мыши.

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

Если кратко подводить итог***** всему сказанному в этих абзацах, что я бы сказал так. Если вы, как разработчик задумались над удобством использования вашего продукта не на стадии разработки, а гораздо позднее, то можно с уверенностью утверждать, что чем дальше вы от точки старта, тем больше затрат и усилий придется приложить, чтобы внести одно «элементарное» исправление. Это касается как общей логики функционирования, так и интерфейса в целом. Копеечная ошибка на старте всегда выливается миллионные затраты на ее исправление на финише.

***** Комментарий автора.

Часто в процессе создания возникает иллюзия «понятности», – это состояние, в котором разработчик настолько проникается идеей продукта и его тонкостями, что ему начинает казаться, что и другим также все очевидно и понятно в функционале создаваемого продукта, как и ему самому. На деле же все выходит наоборот, – даже знающего и опытного пользователя всегда требуется обучать и отвечать на такие вопросы, которые с точки зрения разработчика находятся в ряду «элементарных».

Необходимо как можно раньше начинать глядеть на ваше творение со стороны пользователя и делать это чаще и не просто глядеть (любоваться), а пытаться использовать все то, что вы создали, именно как пользователь. Забыть все, что известно о «внутреннем содержимом» продукта и стать неопытным пользователем, задающим извечные детские вопросы: «Как?» и «Почему?». Поверьте мне, это правило очень и очень часто помогает увидеть такие интересн