Text
                    1ЬПУ w* ЮЛИЙ КЕТКОВ
< ' АЛЕКСАНДР КЕТКОВ
МИХАИЛ ШУЛЬЦ
Т
ПРОГРАММИРОВАНИЕ,
ЧИСЛЕННЫЕ МЕТОДЫ
Интегральная
среда разработки " -• *V .
i *•**
v:
Графическое ?, •' 3* г
представление данных ^ *>
Программирование
вычислительных процессов
Визуализация
трехмерных объектов
Линейная алгебра . у
*
■4~t>
дифференцирование
и интегрирование
Нелинейные уравнения
и оптимизация
\
Численное j ' к
\t
цД
МАСТЕР


Юлий Кетков Александр Кетков Михаил Шульц MATLAB7 ПРОГРАММИРОВАНИЕ, ЧИСЛЕННЫЕ МЕТОДЫ Санкт-Петербург «БХВ-Петербург» 2005
УДК 681.3.06 ББК 32.973.26-018.2 К37 Кетков 10. Л-, Кетков А. Ю., Шульц М. М. К37 MATLAB 7: программирование, численные методы. — СПб.: БХВ-Петербург, 2005. — 752 с: ил. ISBN 5-94157-347-2 Книга посвящена описанию программных средств разработки математического обеспечения п среде MATLAB. Особое внимание уделяется вопросам проектирования пользовательских приложений, представления данных с максимальным использованием средств программирования и отладки приложений, а также увязке программ решения задач линейной алгебры, дискретной математики, математического анализа с основными идеями соответствующих алгоритмов. Для инженеров, студентов и преподавателей вузов УДК 681.3.06 ББК 32.973.26-018.2 Группа подготовки издания: Главный редактор Екатерина Кондукова Зам. главного редактора Евгении Рыбаков Зав. редакцией Григорий Добнн Редактор Анна Кузьмина Компьютерная верстка Нотами Смирновой Корректор Наталия Першакова Дизайн обложки Игоря Цыру./ьникова Зав. производством Николай Тверских Лицензия ИД No 02429 от 24.07.00. Подписано в печать 22.03.05. Формат 70x100Vle. Печать офсетная. Усл. печ. л. 60.63, Тираж 3000 экз. Заказ № 899 "БХВ-Петербург". 194354, Санкт-Петербург, ул. Есенина, 5Б. Санитарно-эпидемиологическое заключение на продукцию N» 77,99.02.953.Д,006421.11.04 от 11.11.2004 г. выдано Федеральной службой по надзору в сфере защиты прав потребителей и благополучия человека. Отпечатано с готовых диапозитивов в ГУП "Типография "Наука" 199034, Санкт-Петербург, 9 линия, 12 ISBN 5-94157-347-2 © Кетков Ю. Л., Кетков А. Ю., Шульи М. М.. 2005 © Оформление, издательство "БХВ-Петербург", 2005
Оглавление Предисловие 1 Глаиа 1. Краткий обзор 3 1.1. Немного истории 3 1.2. Пакет MATLAB 7 и его расширения 5 Глава 2. Пошаговые вычисления в командном окис 13 2.1. Путешествие по среде MATLAB 7 13 2.2. Переменные рабочего пространства , 20 2.3. Скаляры или массивы? Индексированные переменные 22 2.4. Выбор формата отображения числовых данных 25 2.5. Арифметические выражения , 29 2.5.1. Некоторые свойства вещественных данных 29 2.5.2. Специфика использования комплексных величин 30 2.5.3. Числовые матрицы и векторы, специфика представления 33 2.5.4. Специфика выполнения арифметических и логических операций 37 2.5.5. Использование элементарных математических функций 39 2.6. Построение графиков функций одной переменной 43 2.6.1. Простые графики в декартовых координатах 43 2.6.2. График функции в полярных координатах 50 2.6.3. Использование логарифмического масштаба 52 2.6.4. Построение графика функции на заданном интервале 52 2.6.5. Средства управления в графическом окне 55 2.6.6. Редактирование графиков 60 Меню Edit 60 Меню View 67 Меню Insert 69 Меню Tools 69 2.6.7. Включение графиков в отчетную документацию 76 2.7. Деловая графика 77 2.7.1. Плоские столбиковые диаграммы 77 2.7.2- Объемные столбиковые диаграммы 81 2.7.3. Круговые диаграммы S3 2.7.4. Площадные диаграммы 86
IV Оглавление Глава 3. Типы данных 89 3.1. Иерархия типов данных в MATLAB 89 3.1.1. Символьные массивы (char arrays) 90 3.1.2. Целочисленные данные в MATLAB 92 3.1.3. Вещественные данные с одинарной точностью (single arrays) 98 3.1.4. Разреженные матрицы (sparse arrays) 100 3.1.5. Структуры и массивы структур (struct arrays) 101 3.1.6. Массивы ячеек (cell arrays) 104 3.1.7. Массивы указателей на функции (function handle arrays) 105 3.1.8. Логические массивы (logical arrays) 106 3.1.9. Создание массивов из данных разного типа 107 3.2. Программа тестирования данных 108 3.3. Анализ типа данных и состояния элементов массивов 113 3.4. Редактирование массивов 119 Глава 4. Программирование вычислительных процессов 123 4.1. Скрипты и функции 123 4.2. Специфика выполнения операций 127 4.3. Синтаксис операторов MATLAB 127 4.4. Ввод числовых и символьных данных 133 4.5. Вывод результатов вычислений 134 4.6. Типы функций 135 4.7. Параметры функций 137 4.8. Функции era/ и feval 144 4.9. Специфика работы в редакторе m-файлов 146 4.9.1. Меню Text 148 4.9.2. Меню Debug 149 4.9.3. Меню Edit 152 4.10. Отладочные команды 155 4.11. Анализ эффективности программы 160 Глава 5. Обработка символьных данных 165 5.1. Создание символьных объектов 165 5.2. Конкатенация строк 171 5.3. Сравнения символьных данных 174 5.4. Поиск и замена 178 5.5. Преобразования к верхнему и нижнему регистрам 183 5.6. Преобразования строк и чисел 183 5.7. Форматные преобразования (sprint/, sscanf) ..192 5.8. Регулярные выражения и поиск., 198 Глава 6. Работа с файлами 207 6.1. Подготовка файла к работе 209 6.2. Завершение работы с файлами 212
Оглавление V 6.3. Контроль за исчерпанием данных 212 6.4. Работа с двоичными файлами 213 6.4.1. Чтение данных из двоичного файла 214 6.4.2. Запись в двоичный файл 220 6.5. Работа с текстовыми файлами , 223 6.5.1. Последовательное чтение строк из текстового файла 224 6.5.2. Последовательное чтение нескольких символов из файла 224 6.5.3. Форматирование выводимой строки 225 6.5.4. Чтение данных из текстового файла 234 6.6. Форматные преобразования в оперативной памяти 238 6.7. Анализ ошибок в файловых операциях 238 6.8. Альтернативный доступ к текстовым файлам 239 6.9. Числовые файлы с разделителями 250 Глава 7. Иерархия графических объектов и их свойства 255 7.1. Объект Root 260 7.2. Объект Figure , 266 7.3. Объект Ares 274 7.4. Объект Line 283 7.5. Объект Rectangle 287 7.6. Объект Text. 291 7.7. Объект Image 298 7.8. Поиск объектов 312 Глава 8. Проектирование интерфейса 315 8.1. Динамическое создание интерфейсных элементов 321 8.1.1. Командная кнопка 328 8.1.2. Кнопка, фиксирующаяся в утопленном состоянии 335 8.1.3. Рамки, индикаторы альтернативных и неальтернативных комбинаций 336 8.1.4. Ввод, редактирование и отображение текстов 341 8.1.5. Списки строк 345 8.1.6. Полоса прокрутки 347 8.2. Создание всплывающего меню 350 8.3. Проектирование интерфейса в среде GUIDE 352 8.3.1. Вызов редактора GUIDE ." 353 8.3.2. Управление конструктором графического интерфейса 360 8.3.3. Размещение интерфейсных элементов 365 8.3.4. Инспектор свойств (Property Inspector) 371 8.3.5. Просмотр объектов (Object Browser) 372 8.3.6. Создание меню (Menu Editor) 372 8.3.7. Анатомия файла, создаваемого в среде GUIDE 380 8.3.8. Использование контейнеров 387
VI Оглавление Глава 9. Стандартные диалоговые окна 393 9.1. Диалоговое окно общего назначения (dialog) 394 9.2. Окно с сообщением об ошибке (errordlg) 395 9.3. Окно со справочной информацией (helpdlg) 396 9.4. Стандартное окно для ввода строк (inputdlg) 397 9.5. Окно выбора из списка (listdlg) 399 9.6. Диалоговое окно с сообщением (tnsgbox) 402 9.7. Интерактивная настройка параметров страницы (pagedlg) 403 9.8. Диалоговая страница (pageseitipdlg) 405 9.9. Окно настройки параметров печати (printdlg) 406 9.10. Диалоговое окно с запросом (qtiestdlg) 408 9.11. Выбор имени файла для чтения (uigetjile) 409 9.12. Выбор имени файла для записи (uiput/ile) 412 9.13. Диалоговое окно для выбора цвета (uisetcolor) 413 9.14. Диалог по выбору параметров шрифта (uisetfont) 415 9.15. Диалоговое окно с предупреждением (warndlg) 416 9.16. Полоса прогресса 417 Глава 10. Визуализация трехмерных объектов 421 10.1. Некоторые задачи и алгоритмы трехмерной визуализации 421 10.1.1. Аффинные преобразования и однородные координаты 421 10.1.2. Растеризация векторных изображений 423 10.1.3. Воспроизведение утолщенных линий 424 10.1.4. Устранение невидимых частей изображения 424 10.1.5. Окрашивание граней полигональных моделей 425 10.2. Создание и отображение криволинейных поверхностей 427 10.2.1. Объект типа Surface и его свойства 427 10.2.2. Отображение проволочного каркаса поверхности 432 10.2.3. Отображение закрашенных поверхностей 436 10.2.4. Управление точкой зрения 437 10.2.5. Выбор алгоритма визуализации 438 10.2.6. Освещение поверхностей 440 10.2.7. Построение линий уровня 442 10.3. Формирование и отображение полигональных тел 448 10.3.1. Объект типа Patch и его свойства 448 10.3.2. Закрашивание объектов типа Patch... 455 10.4. Специальные способы закраски. Призрачность 460 10.4.1. Нанесение изображения на поверхность 460 10.4.2. Прозрачные поверхности 462 Глава И. Полиномы 465 11.1. Представление полиномов 465 11.2. Операции над полиномами, представленными вектором коэффициентов , 466
Оглавление VII 11.2.1. Значение полинома 466 11.2.2. Сложение и вычитание , , 467 11.2.3. Умножение и деление 468 11.2.4. Дифференцирование и интегрирование 469 11.2.5. Корни полинома 470 11.3. Операции над полиномами, заданными в символьном виде 471 11.3.1. Значение полинома 471 11.3.2. Сложение и вычитание 472 11.3.3. Умножение и деление 473 11.3.4. Дифференцирование и интегрирование 474 11.3.5. Корни и разложение полинома на множители 476 Глава 12. Линейная алгебра 479 12.1. Основные матричные операции 479 12.2. Скалярное и векторное произведение 481 12.3. Стандартные матрицы, фрагменты и блоки 487 12.4. Простые преобразования матриц 488 12.5. Некоторые классы матриц 490 12.5.1. Симметричные и кососимметричпые матрицы 490 12.5.2. Эрмитовы и косоэрмитовы матрицы 490 12.5.3. Ортогональные (унитарные) матрицы 490 12.6. Специальные матрицы 490 12.6.1. Матрица Гильберта и обратная к ней 490 12.6.2. Матрица Адамара 491 12.6.3. Матрица Паскаля 491 12.6.4. Матрица Теплица 492 12.6.5. Матрица Ганкеля 492 12.6.6. Матрица Вандермонда 493 12.6.7. Магический квадрат 494 12.7. Разложение матриц 494 12.7.1. Разложение Эрмита 494 12.7.2. Скелетное разложение 496 12.7.3. LU-разложение 498 12.7.4. Разложение Холецкого 500 12.7.5. QR-разложение 500 12.7.6. Сингулярное разложение 503 12.7.7. Полярное разложение 504 12.7.8. Разложение Шура 505 12.7.9. Разложение Хессенберга 507 12.7.10. Разложение Жордана 509 12.8. Системы линейных уравнений 511 12.8.1. Основные понятия 511 Существование и единственность решения 511 Обратная и псевдообратная матрицы 511
Оглавление 12.8.2. Решение совместной системы 512 12.8.3. Псевдорешение несовместной системы 515 12.8.4. Некоторые приложения 517 Линейные матричные уравнения 517 Система уравнений с формируемой матрицей 519 12.9. Проблема собственных значений 522 12.9.1. Характеристический полином 522 Собственные векторы 523 12.9.2. Вычисление собственных значений 524 Случай кратных корней 525 Случай комплексных корней 526 12.9.3. Обусловленность матрицы , 527 12.10. Линейная алгебра и новые тины данных 529 Глава 13. Интерполяция и аппроксимация 535 13.1. Интерполяционный полином 535 13.2. Сплайны 539 13.2.1. Стандартные сплайны MATLAB 543 13.2.2. Сглаженные сплайны 544 13.2.3. Сплайны с заданными условиями на концах 546 13.3. Параметрическая аппроксимация 549 13.4. Двумерная аппроксимация 553 13.4.1. Аппроксимация на прямоугольной сетке 553 13.4.2. Аппроксимация с помощью, триангуляции 555 Глава 14. Численное дифференцирование и интегрирование 559 14.1. Конечные разности 559 14.2. Численное дифференцирование функций одной переменной 560 14.3. Численное дифференцирование функций двух переменных 562 14.4. Численное интегрирование 563 14.5. Задача Коши для обыкновенных дифференциальных уравнений 572 14.6. Краевая задача для обыкновенных дифференциальных уравнений 580 14.7. Дифференциальные уравнения неявного типа 588 Глава 15. Нелинейные уравнения и оптимизация 595 15.1. Корень уравнения с одним неизвестным 595 15.2. Решение систем нелинейных уравнений 599 15.3. Минимизация унимодальной функции одной переменной 611 15.4. Многомерная безусловная минимизация 614 15.4.1. Функция fminsearch 614 15.4.2. Функция fminunc 618 15.4.3. Функция Isqnonlin 624 15.4.4. Функция fminimax 629
Оглавление IX 15.5. Условная минимизация 637 15.5.1. Функция fmincon 638 15.5.2. Функции Isqnonlin wfiiiimmax 646 15.6. Управление итерационными процессами 649 Глава 16. Математическое программирование 653 16.1. Линейное программирование 653 16.2. Бинарное линейное программирование 658 16.3. Решение матричных игр 662 16.4. Квадратичное программирование 667 Глава 17. Метод Монте-Карло 675 17.1. Генерация случайных данных 676 17.2. Элементы математической статистики 677 17.3. Линейная интерполяция в многомерном кубе 678 17.4. Вычисление кратных интегралов 683 17.5. Решение уравнений в частных производных 686 17.6. Моделирование случайных процессов 695 17.7. Случайный поиск 699 Приложения 70S Приложение 1. Помощь в системе MATLAB 707 Поиск по ключевым словам 708 Использование Help-навигатора 710 Поиск функций 713 Приложение 2. Указатель свойств графических объектов 715 Литература и интернет-источники 723 MATLAB 723 Методы вычислений 725 Интернет 727 Предметный указатель.. 728
Предисловие Система MATLAB представляет собой уникальный сплав универсальных программных и алгоритмических средств с широкой гаммой специализированных приложений. Входной язык и среда программирования MATLAB очень близки к современным системам визуального программирования на базе универсальных алгоритмических языков типа Basic, C++, Java, Object Pascal. По ряду аспектов MATLAB уступает указанным системам (режим интерпретации, небольшой запас визуальных компонентов). Однако с его библиотекой численных методов ни по объему, ни по качеству не может сравниться ни одна из систем профаммирования. Кроме того, в пакете MATLAB тщательно отработаны средства визуализации результатов вычислений и отображения различных графических объектов. На базе ядра MATLAB созданы многочисленные расширения, обеспечивающие моделирование и анализ систем в разнообразных сферах человеческой деятельности. Многие учебные заведения у нас и за рубежом используют MATLAB при подготовке специалистов различного профиля. Для современного инженера и научно-технического работника MATLAB является незаменимым инструментом моделирования и исследования различных прикладных систем, прежде всего, за счет использования готовых решений. Но не менее важно научиться создавать новые приложения, используя программные и алгоритмические средства MATLAB, а также возможность объединения модулей, разработанных в разных системах программирования. Использование системы MATLAB в учебном процессе позволит сблизить дисциплины, связанные с информатикой и численными методами, которые зачастую читаются автономно. Авторы выражают признательность М. В. Шашкову, который на протяжении ряда лет успешно использует систему MATLAB для проектирования и исследования сложных динамических систем. Именно он привлек наше внимание к выразительности программных средств и богатству численных методов пакета MATLAB. Мы очень обязаны и нашим коллегам, специализирующимся в различных разделах прикладной математики, которые помогли нам в формировании глав, связанных с численными методами, и в под-
2 Предисловие боре соответствующих приложений. Среди них преподаватели факультета ВМиК Нижегородского университета — М. А. Антонец, А. И. Гавриков, С. Ю. Городецкий, Н. В. Дерендяев, В. А. Зорин, А. П. Мальцев, В. П. Савельев. Особой благодарности заслуживает А. И. Кузнецов — сотрудник научно-исследовательского института прикладной математики и кибернетики Нижегородского университета, который тщательно прочитал рукопись и проверил практически все примеры программ. Многие его замечания были учтены при подготовке настоящего издания.
Глава 1 Краткий обзор Пакет MATLAB 7 — последняя версия одного из наиболее популярных продуктов фирмы MathWorks, появившаяся на рынке программного обеспечения в июне 2004 г. Его основное назначение — моделирование, анапиз и визуализация динамических процессов, имеющих отношение к разнообразным сферам человеческой деятельности. 1.1. Немного истории Историю появления пакета MATLAB связывают с именем профессора Клива Б. Моулера (Cleve В. Mouler). До перехода в фирму MathWorks он занимался преподавательской и научно-исследовательской деятельностью на кафедрах математики и в компьютерных центрах ряда университетов США (Ыыо-Мехико, Мичиган, Стэнфорд). Он соавтор ряда книг, переведенных на русский язык ([66, 67]). Примерно 30 лет назад Моулер принимай участие в разработке пакетов программ на языке Fortran для решения задач линейной алгебры (UNPACK) и исследованиях проблемы собственных значений матриц (EISPACK). В 1980 г. на международной конференции AFIPS он представил доклад "Design of an interactive matrix calculator", в котором, по- видимому, впервые было озвучено название MATLAB. В реферативном журнале "Автоматика и вычислительная техника" (реферат 6Б200 за 1980 г.) по поводу этого доклада появилась следующая аннотация: "Приведено формальное описание (с помощью синтаксических диаграмм) входного языка интерактивной программы MATLAB, предназначенной для матричных вычислений. Программа MATLAB обрабатывает прямоугольные матрицы, элементами которых являются комплексные числа. Данные вводятся либо перечислением элементов, либо в цикле при помощи операторов for и while, либо считыванием из внешнего файла, либо после выполнения внешней программы. Для выполнения матричных вычислений помимо 37 встроенных функций программы MATLAB предусмотрен простой способ обращения к пакету ПП EISPACK (70 программ выполнения матричных вычислений) и пакету
4 Глава 1 LINPACK (40 программ анализа и решения систем линейных алгебраических уравнений) и связанных с ними матричных вычислений. Программа написана на языке Fortran и может работать под управлением любой системы, допускающей выполнение программ в диалоговом режиме". Второе рождение пакета MATLAB связывают с Джеком Лигглом (Jack Little) — нынешним президентом фирмы MathWorks, который в начале 80-х годов прошлого века перенес программу MATLAB на более современные вычислительные платформы VAX, Macintosh и IBM PC. Дальнейшее развитие пакета происходило под эгидой MathWorks, однако к расширению состава пакета и сфер его применения были привлечены коллективы высококвалифицированных математиков и инженерно-технических работников Старого и Нового света. Об этом свидетельствуют ссылки на многочисленные книги и перечень благодарностей, которые можно обнаружить в справочных файлах по всем продуктам пакета. С момента основания фирмы (1984 г.) К. Моулер является ее бессменным научным руководителем. Модернизацию и программное сопровождение пакета MATLAB обеспечивают более 1000 сотрудников MathWorks. К концу 2004 г. реализации пакета MATLAB насчитывают следующие версии: 1. MATLAB 5 — декабрь 1996 г. 2. MATLAB 5.1 — май 1997 г. 3. MATLAB 5.3 (Release 11, Rll) — январь 1999 г. 4. MATLAB 6.0 (R12) — ноябрь 2000 г. 5. MATLAB 6.1 (R12.1) - июнь 2001 г. 6. MATLAB 6.5 (R13) - июнь 2002 г. 7. MATLAB 6.51 (R13SP1) — август 2003 г. 8. MATLAB 7.0 (R14) - июнь 2004 г. Пакет MATLAB распространяется в двух модификациях — профессиональная версия и облегченный вариант, ориентированный на использование в учебном процессе. На самом деле даже в профессиональной версии некоторые расширения пакета приобретаются по отдельной лицензии. В нашей стране информация по вопросам использования и распространения пакета доступна на сайтах www.softline.ru, www.matlab.ru и www.exponenta.ru. Регулярные научные семинары, посвященные возможностям пакета MATLAB, проводятся Институтом Проблем Управления РАН РФ и Консультационным центром MATLAB компании Softline. О популярности пакета MATLAB свидетельствуют более 600 монографий, учебных и практических пособий, изданных за рубежом. Отечественная ли-
Краткий обзор 5 тература насчитывает примерно в 15 раз меньше наименований (ели список литературы и интернет-источников). Одной из наиболее важных особенностей пакета MATLAB является его открытость. В его комплекте поставляется довольно много исходных текстов программных модулей — функций, тестовых примеров. Это предоставляет возможность пользователям разобраться в алгоритмах, модифицировать их для своих приложений и расширять сферу применения пакета. 1.2. Пакет MATLAB 7 и его расширения Перечислим принципиальные новинки MATLAB 7: П 12 новых компонентов, расширяющих сферу приложений пакета MATLAB и повышающих функциональные возможности прежних компонентов; П 28 компонентов предыдущей версии подверглись существенной модификации; П в ряде приложений (линейная алгебра, быстрые преобразования Фурье, моделирование в среде Simulink) реализована поддержка вычислений с вещественными данными одинарной точности; П появилась возможность обрабатывать целочисленные массивы большой размерности за счет использования целочисленной арифметики; П существенно изменен интерфейс среды MATLAB и некоторых сервисных систем; □ расширились возможности по управлению графическими окнами; П исправлены замеченные ошибки. Полный перечень нововведений и исправлений составляет документ "MATLAB 7.0 Release Notes" объемом 274 с. Пакет MATLAB 7 предъявляет повышенные требования к РС-совместимому оборудованию и программному обеспечению: П персональный компьютер на базе процессоров Pentium III, Pentium 4, Pentium M, Xeon. AMD Athlon, Athlon XP, Athlon MP; □ операционная система Microsoft Windows XP, Windows NT 4.0 (Service Pack 5 или 6a) , Windows 2000 (Service Pack 3 или 4); П CD-ROM для инсталляции с оптического диска; П оперативная память не менее 256 Мбайт (рекомендуется 512 Мбайт); □ размер дисковой памяти зависит от количества установленных расширений и объема документации и формате PDF. Программа установки информирует вас об объеме дисковой памяти, необходимой для включения
6 Глава 1 того или иного компонента пакета. В средней комплектации MATLAB займет на винчестере порядка 1 Гбайт; П монитор с поддержкой минимум 256 цветов, рекомендуется графический адаптер (16, 24 или 32 битов), поддерживающий стандарт OpenGL. В состав дополнительных рекомендаций входят: □ операционная система должна поддерживать карту графического ускорителя, принтер и звуковую карту; П Microsoft Word (Office 2000) или Office ХР необходимы для функционирования MATLAB Notebook; □ протокол TCP/IP требуется на всех платформах для использования лицензионного сервера. Для генерации собственных тех-файлов понадобится один из следующих трансляторов: П Compaq Visual Fortran (версии 5.0, 6.1 или 6.5); П Microsoft Visual C/C++ (версии 5.0, 6.0 или 7.0); □ Borland C/C++ (версии 5.0 или 5.02); □ Borland C++Builder (версии 3.0, 4.0, 5.0 или 6.0); □ WATCOM (версии 10.6 или 11); ■П Lcc 2.4 (bundled with MATLAB). Для чтения и/или печати online-документации потребуется Netscape Navigator (версия 4.0 или выше) или Microsoft Internet Explorer (версия 4.0 или выше), Adobe Acrobat Reader (версия 3.0 или выше). Одним из наиболее важных приложений пакета MATLAB является проектирование, имитация и анализ различных динамических систем. До появления первых цифровых вычислительных машин (ЦВМ) большинство задач, связанных с созданием и исследованием различных систем автоматического регулирования, решались на аналоговых вычислительных машинах (АВМ). В основе АВМ лежали динамические аналогии между поведением различных акустических, электрических и механических звеньев, описываемых однотипными системами дифференциальных уравнений. АВМ представляли собой набор электронных блоков (усилителей, сумматоров, умножителей, интеграторов, задержек и различных нелинейностей), которые с помощью коммутационной панели соединялись в схему, эквивалентную исследуемой конструкции. А затем с помощью осциллографов и самописцев фиксировалось и изучалось поведение напряжений и токов в различных узлах электрической модели исследуемого объекта. В середине 50—60-х годов прошлого столетия пользовались большой популярностью настольные интефаторы типа ИПТ-5 и МПТ-9, относительно небольшие лабораторные установки ЭМУ-8, ЭМУ-10 и такие гиганты, как
Краткий обзор 7 МН-8, занимавшие площади по 60—80 кв. м. Самой главной оценкой мощности АВМ был максимальный порядок системы дифференциальных уравнений, которую можно было собрать из имеющихся блоков. И колебался он в диапазоне от 5—6 до 30—40. К основным недостаткам АВМ относились большая трудоемкость в коммутации блоков, нестабильность их поведения (дрейф нуля усилителей), относительно малая точность результатов и затяжной характер исследования. Однажды собранная и отлаженная схема коммутации блоков должна была сохраняться на протяжении времени исследования данной системы. На более поздних АВМ появились сменные коммутационные панели. Повышению эффективности моделирования содействовали гибридные аналого-цифровые вычислительные системы (ГВС "Русалка"). Однако точность вычислений, обеспечиваемая аналоговыми компонентами, оставляла желать лучшего. Пакет Simulink, самый родной среди расширений системы MATLAB (кнопка для его запуска вынесена па панель инструментов системы), повторяет идею АВМ на самом современном уровне. Он использует богатую библиотеку динамических звеньев с различными передаточными функциями, располагает визуапьными средствами сборки эквивалентной модели, обладает большим набором вычислительных алгоритмов, обеспечивает высокую точность и качественное отображение характеристик изучаемых процессов. Наибольшее количество отечественных публикаций посвящено именно этому пакету [1, 2, 7, 8, 12, 14, 19, 20, 39]. На его базе построено довольно много расширений системы MATLAB. Их наименования, как правило, включают фирменную аббревиатуру Blockset, что можно трактовать как набор блоков — моделей (файлы с расширением mdl), участвующих в конструировании моделируемых систем. Другие расширения MATLAB используют более распространенную аббревиатуру Toolbox (дословно — ящик с инструментами). Как правило, основными компонентами таких расширений являются средства решения различных задач — математические методы, визуализация результатов вычислений. Большая часть этих приложений представлена m-файлами — программами на входном языке MATLAB. Полный перечень дополнительных компонентов версии MATLAB 7 приведен в табл. 1.1. Некоторые из них являются автономными продуктами, другие эксплуатируются в комбинации с определенным подмножеством расширений. По номеру версии компонента можно судить как о его "возрасте", так и об интенсивности его поддержки. Из приведенного перечня видно, что старейшими приложениями системы MATLAB являются средства обработки сигналов, моделирования управляющих систем, имитации различных устройств в режиме реального времени. В первой колонке символом * отмечены компоненты, подвергшиеся серьезной модификации. Новые компоненты отмечены символами **.
8 Глава 1 Таблица 1.1 № п/п Компонент MATLAB Назначение 1* 2 3** 4 5* 6* 7 8 9 Simulink, ver 6,0 Aerospace Blockset, ver 1.6 Bioinformatics Toolbox, ver 1.1 CDMA Reference Blockset, ver 1.1 Communications Blockset, ver 3.0 Communications Toolbox, ver 3.0 Control System Toolbox, ver 6.0 Curve Fitting Toolbox, ver 1.1.1 Data Acquisition Toolbox, ver 2.5 10* Database Toolbox, ver 3.0 11 Datafeed Toolbox, ver 1.5 12 Dials & Gauges Block- set, ver 1.2 13 Embedded Target Infineon C166 Microcontrollers, ver 1.1 14 Embedded Target for Motorola HC12,, ver 1.1 15* Embedded Target for Motorola MPC555, ver 2.0 Моделирование и анализ динамических систем Моделирование летательных аппаратов, ракет и двигательных установок (на базе Simulink) Математические методы анализа экспериментальных данных в биологии и генетике Проектирование и моделирование беспроводных коммуникационных систем в соответствии со стандартом IS-95A (code division multiple access, CDMA) Библиотеки функций для Communications Toolbox (модуляция, кодирование, декодирование) Разработка коммуникационных систем и их моделирование в реальном масштабе времени Моделирование, анализ и проектирование систем автоматического регулирования с обратной связью Обработка экспериментальных данных (аппроксимация, сглаживание, интерполяция, экстраполяция) Среда для поддержки измерительных комплексов, подключенных к персональному компьютеру (ПК). Организация обмена данными с аналоговыми и цифровыми подсистемами, включая цифроанапо- говые преобразования Анализ и визуализация информации, хранящейся в базе данных (БД). Отбор данных с использованием запросов на языке SQL Организация связи с серверами финансовых данных Библиотека графических примитивов для формирования панелей управления с изображениями различных шкал и измерительных приборов Проектирование и моделирование измерительно- управляющих комплексов на базе микроконтроллеров С166 Проектирование и моделирование измерительно- управляющих комплексов на базе микроконтроллеров фирмы Motorola Проектирование и моделирование измерительно- управляющих комплексов на базе микроконтроллеров фирмы Motorola
Краткий обзор 9 Таблица 1.1 (продолжение) № п/п Компонент MATLAB Назначение 16 Embedded Target for OSEC/VDX. ver1.1 17** Embedded Target for Texas Instruments C2000 DSP, ver 1.0 18* Embedded Target for Texas Instruments C6000DSP, ver 2.1 19 Excel Link, ver 2.2 20 21** 22* 23* 24 25 26 27** Extended Symbolic Math, ver 3.1 Filter Design HDL Coder, ver 1.0 Filter Design Toolbox, ver 3.0 Financial Derivatives Toolbox, ver 3.0 Financial Time Series Toolbox, ver 2.1 Financial Toolbox, ver 2.4 Fixed-Income Toolbox, ver 1.0.1 Fixed Point Toolbox, ver 1.0 28 Fuzzy Logic Toolbox, ver 2.1.3 29 GARCH Toolbox, ver 2.0.1 30** Genetic Algorithm and Direct Search Toolbox, ver 1.0.1 Проектирование и моделирование измерительно- управляющих комплексов на базе микроконтроллеров OSEC/VDX Проектирование и моделирование измерительно- управляющих комплексов на базе микроконтроллеров фирмы Texas Instruments Проектирование и моделирование измерительно- управляющих комплексов на базе микроконтроллеров фирмы Texas Instruments Организация взаимодействия между функциями MATLAB и электронной таблицей Microsoft Excel Расширенный пакет аналитических вычислений HDL-кодирование в цифровых фильтрах Проектирование, имитация и анализ цифровых фильтров Анализ и визуализация процентных ставок, финансовых производных и рисков Анализ данных финансовых рынков методом временных рядов Интегрированная среда для решения задач управления финансами и графического представления результатов анализа Прогнозирование фиксированного дохода Выполнение арифметических операций над нестандартными форматами чисел (целочисленные, длиной 1, 2, 4 байта; вещественные с одинарной точностью) Моделирование и анализ систем на базе аппарата "нечеткой логики" Анализ изменчивости на финансовых рынках с использованием одномерных GARCH-моделей (General Autoregressive Conditional Heteroscedasticity) Генетический алгоритм и прямой поиск
10 Глава 1 Таблица 1.1 (продолжение) № п/п Компонент MATLAB Назначение 31 Image Acquisition Toolbox, ver 1.5 32 Image Processing Toolbox, ver 3.2 33* Instrument Control Toolbox, ver 2.9 34 LMI Control Toolbox, ver 1.0.9 35 Link for Code Composer Studio, ver 1.3.1 36** Link for ModelSim, ver 1.1.1 37 MATLAB Builder for COM, ver 1.1 38 MATLAB Builder for Excel, ver 1.2 39* MATLAB Compiler, ver 4.0 40* MATLAB Report Generator, ver 2.0 41 MATLAB Web Server, ver 1.2.3 42* Mapping Toolbox, ver 2.0.2 43* Model Predictive Control Toolbox, ver 2.0 44 Model-Based Calibration Toolbox, ver 2.1 45 Mu-Analysis and Synthesis Toolbox, ver 3.0.8 46 Neural Network Toolbox, ver 4.0.3 Организация обмена графическими данными Обработка изображений (анализ, фильтрация, двумерные преобразования, восстановление и т. п.) Обмен данными и управляющими сигналами с периферийными приборами в формате протоколов IEEE-488, HPIB, VISA Моделирование и анализ систем, описываемых линейными матричными неравенствами (Linear Matrix Inequality, LMI) Организация связи между MATLAB и интегрированной средой разработки (IDE) фирмы Texas Instruments (Code Composer Studio, CCS) Организация связи между MATLAB и средой твердотельного моделирования ModelSim Компилятор проектов MATLAB в СОМ-объекты Конвертирование программ MATLAB в модули Excel Компилятор m-файлов в коды С, C++ Создание отчетов в различных форматах (RTF, HTML, XML, SGML), включая специфику представления данных и моделей Сервис Web-сервера, позволяющий пользователям Интернета выполнять на сервере MATLAB-приложения Обработка и визуализация цифровых карт местности Анализ и управление сложными системами с большим количеством входных и выходных данных Проектирование эксперимента, статистическое моделирование и калибровка сложных систем Современные методы анализа и синтеза устойчивых линейных систем управления высокого порядка Применение искусственных нейронных сетей для решения трудноформализуемых задач
Краткий обзор 11 Таблица 1.1 (продолжение) № Компонент MATLAB п/п Назначение 47** ОРС Toolbox, ver 1.0 48* Optimization Toolbox, ver 3.0 49 Partial Differential Equation Toolbox, ver 1.0.5 50** RF Blockset, ver 1.0 51** RF Toolbox, ver 1.0 52 Real-Time Windows Target, ver 2.5 53* Real-Time Workshop, ver 6.0 54* Real-Time Workshop Embedded Coder, ver 4.0 55 Robust Control Toolbox, ver 2.0.10 56* Signal Processing Blockset, ver 6.0 57 Signal Processing Toolbox, ver 6.0 58 SimMechanics, ver 2.2 59 SirnPowerSystems, ver 3.1 60 Simulink Accelera-tor, ver 6.0 61** Simulink Control Design, ver 1.0 Поддержка промышленных стандартов для обмена данными в системах реального времени (OLE for Process Control, ОРС) Поиск экстремумов функций многих переменных при наличии ограничений, решение нелинейных уравнений Поиск и визуализация решений систем дифференциальных уравнений в частных производных Моделирование и исследование беспроводных систем связи Моделирование и исследование беспроводных систем связи Создание моделей с интерфейсом в стиле Simulink и управление ими в режиме реального времени Генерация программ в расширенном С-формате по блочным диаграммам пакета Simulink Оптимизация программ, изготовленных пакетом Real-Time Workshop, по использованию памяти, по скорости работы, по простоте интерфейса, по удобочитаемости кода Анализ и синтез систем управления, устойчивых по отношению к случайным воздействиям (робастное управление) Библиотеки Simulink, предназначенные для проектирования и моделирования систем цифровой обработки сигналов. Прежнее название — DSP Block- set (Digital Signal Processing, DSP) Обработка цифровых и аналоговых сигналов Моделирование твердотельных механических систем на базе аппарата Simulink Моделирование электрических силовых систем на базе аппарата Simulink Повышение производительности программ, созданных в среде Simulink Управление процессом построения моделей в среде Simulink
12 Глава 1 Таблица 1.1 (окончание) № Компонент MATLAB п/п Назначение 62* Simulink Fixed Point, ver 1.0 63** Simulink Parameter Estimation, ver 1.0 64* Simulink Report Generator, ver 2.0 65* Simulink Response Optimization, ver 2.0 66** Simulink Verification and Validation, ver 1.0 67 Spline Toolbox, ver 3.2.1 68* Stateflow, ver 6.0 69* Stateflow Coder, ver 6.0 70* Statistics Toolbox, ver 5.0 71 Symbolic Math Toolbox, ver 3.1 72* System Identification Toolbox, ver 6.0.1 73* Virtual Reality Toolbox, ver 4.0 74* Wavelet Toolbox, ver 3.0 75 xPC Target, ver 2.5 76 xPC Target Embedded Option, ver 2.5 Обеспечение расчетов с одинарной точностью в среде Simulink (прежнее название Fixed-Point Blockset) Подбор параметров моделей в среде Simulink Создание отчетов с включением данных и моделей пакета Simulink Проектирование, имитация и анализ систем автоматического регулирования с нелинейными ограничениями (прежнее название Nonlinear Control Design Blockset) Контроль за правильностью и допустимостью моделей в среде Simulink Библиотека процедур для сплайн-аппроксимации плоских кривых и криволинейных поверхностей Моделирование систем, управляемых событиями, на базе теории конечных автоматов Оптимизация программ, построенных на базе моделей Stateflow Набор методов вероятностного анализа и визуализации результатов статистических исследований Символьные вычисления на базе ядра пакета Maple Идентификация систем (восстановление математической модели) на основе анализа входных и выходных сигналов Создание трехмерных сцен виртуальной реальности на базе языка VRML (Virtual Reality Modeling Language) Непрерывные и дискретные вейвлет- преобразования для анализа и синтеза сигналов и изображений различной природы Моделирование и тестирование систем реального времени в автономном режиме на целевом компьютере или в связке с сервером
Глава 2 Пошаговые вычисления в командном окне 2.1. Путешествие по среде MATLAB 7 По умолчанию после запуска пакета MATLAB 7 на экране появляется комбинированное окно, включающее четыре наиболее важные панели — Command Window (Окно команд), Command History (История команд). Workspace (Рабочее пространство) и Current Directory (Текущий каталог). Две последние панели закрывают друг друга, и для выдвижения нужной панели на передний план следует щелкнуть по соответствующей вкладке. Три окна, вписанные в главное окно системы (рис. 2.1), "поставлены на якоря". Они передвигаются вместе с главным окном системы, вместе с ним изменяют свои размеры, границы между окнами можно передвигать. Каждое из них можно снять с якоря (кнопки Undock (Отстыковать) |QJ, размещенные в правых верхних углах окон), и тогда оно может занимать автономную позицию на экране'. Вообще, самой используемой панелью является Command Window (Окно команд). В ней набираются команды пользователя, подлежащие немедленному исполнению. Здесь же выдаются результаты выполненных команд. В командном окне можно обратиться за помощью по поводу того или иного термина с помощью одной из команд — doc, help или lookfox. Присутствие двух других окон во время сеанса работы только загромождает экран, и их целесообразно закрыть (такого рода операции выполняются не только кнопками, но и командами меню Desktop (Рабочий стол)). Окно Workspace (Рабочее пространство) отображает текущий набор переменных, заведенных пользователем в командном окне. Здесь можно увидеть их имена (колонка Name (Имя)), значения скалярных переменных (колонка Value (Значение)) и тип представляемых данных (колонка Class (Тип данных)). Точно такую же информацию можно увидеть в командном окне после исполнения команды whos. Поэтому постоянное присутствие окна Workspace (Рабочее пространство) на экране вряд ли оправдано. В него
14 Глава 2 удобно заглядывать в тех случаях, когда вам понадобится откорректировать значения элементов какого-либо массива с помощью Array Editor (Редактор массивов). Это новый инструмент, появившийся в 7-й версии. Для его вызова достаточно щелкнуть по имени переменной в поле Workspace (Рабочее пространство). -JfcMATLAB File Edit Debug Desktop Window Help ■Shortcuts ijrj How to Add £j y^a'sNavy Workspace |_) x US-» V- ф 1 f* ' til - Sto*|:-.^jLl Name '- 1 Value j Class LD an: 1 double EBc 0.87758 double Els 0 47943 double <1 1 M Command History щx ,.- . 1 . - 11: ■s=sin(0.5>; —c=cos(D.5) ; ■3*S+C*C Ф Start 1 Command window НПО 0* » s=sinitl.5) ; » c=cos (0-5); » s*s+c*c ans = 1 » Рис. 2.1. Общий вид главного окна пакета MATLAB 7 Окно Command History (История команд) хранит все команды, набираемые пользователем, однако в отличие от содержимого Command Window (Окно команд) сюда не попадают сообщения системы и результаты вычислений. Эта информация может оказаться полезной для формирования программы, исполняемой в автоматическом режиме. Совершим беглый экскурс по командам главного меню. Команды меню File (Файл) (рис. 2.2) выполняют обычные функции для большинства систем программирования. Первая группа команд обеспечивает переход в режим ввода новой программы (New (Создать)) или извлечение из дискового файла ранее сохраненной программы (Open (Открыть)). Команда Close Command Window (Закрыть окно команд) дублирует соответствующую кнопку в Command Window (Окно команд). Команды второй группы позволяют сохранить значения всех переменных рабочего пространства в дисковом файле (Save Workspace As (Сохранить рабочее пространство как)) или импортировать ранее сохраненные данные (Import Data (Импортировать данные)).
Пошаговые вычисления в командном окне 15 Flle'l New Open... Close Command Window Import Data,.. Save Workspace As.., SetPeth... Preferences... Page Setup... Prin^:... flirj --.:-1(.-1:-...: . 1 C:\...p5\work\array2vec.m 2 H:\...AB7\work\untiaed.m 3 C:\MATLAB6p5\work\dlfF2.m 4 C;\MATLAB6D5\workl\test.m ExitMATLAB t Ctrl+O Ctrl+S Orl+Q Рис. 2.2. Команды меню File Команда Set Path (Задать путь) позволяет пополнить список каталогов, просматриваемых системой, или изменить порядок их просмотра. Настройка параметров системы выполняется в окне Preferences (Предпочтения). Четвертая группа команд — традиционная для большинства систем. Она обеспечивает получение твердой копии с предварительной настройкой параметров бумаги и принтера. Под ними расположена часть меню со списком последних файлов, с которыми работал пользователь. Размер этого списка регулируется, и его основное назначение — ускорить выборку файлов, открывавшихся в предыдущем сеансе. Меню Edit (Правка) (рис. 2.3) содержит характерный для любого редактора набор команд по вырезанию (Cut (Вырезать)), копированию (Сору (Копировать)), вставке (Paste (Вставить)), Paste Special (Специальная вставка)) и удалению (Delete (Удалить)) выделенных фрагментов текстов или графических объектов. Команда Select All (Выделить все) выделяет текстовый или графический объект целиком. Команды Undo (Отменить) и Redo (Повторить) используются, соответственно, для отмены только что совершенного действия или отказа от предшествующей отмены. С помощью команды Find (Найти) можно найти текстовый фрагмент и, при необходимости, произвести его замену. Последняя группа команд позволяет произвести очистку соответствующих окон. Выполнение команд Clear Command Window (Очистить окно команд).
16 Глава 2 Clear Command History (Очистить окно истории команд) и Clear Workspace (Очистить переменные рабочего пространства) по умолчанию сопровождается запросом о подтверждении. Эти сообщения системы можно подавить, устанавливая соответствующие параметры в окне Preferences (Предпочтения). Edit] Undo CJ_ Copy Paste Paste Special... Select All Delete. Find... Find Files... ■ Clear Command Window Clear Command History Clear Workspace Ctrl+Z Ctrl+vv Alt+W Ctrl+Y Ctrl+D -.. : Рис. 2.3. Команды меню Edit На командах меню Debug (Отладка) мы остановимся подробнее в разд. 4.9. Из главного меню MATLAB 7 исчез привычный для пользователей предыдущих версий набор команд меню View (Вид). Большинство из них перекочевало в меню Desktop (Рабочий стол) — рис. 2.4. Команда Undock Command Window (Снять с якоря окно команд) разъединяет состыкованные окна и позволяет Command Window (Окно команд) перемещаться самостоятельно. Команда Desktop Layout (Разметка рабочего стола) определяет количество и расположение одновременно видимых панелей среды. Вы можете выбрать конфигурацию среды по умолчанию (Default), которая была приведена на рис. 2.1, или сохранить на экране только окно команд (Command Window Only). Команда History and Command Window (Окна истории и команд) позволяет сохранить два окна — историю команд и окно команд. Команда All Tabbed (Со вкладками) располагает на экране все окна (рис. 2.5). При этом одно из окон находится на переднем плане, а любое из оставшихся выходит на передний план после щелчка по соответствующей вкладке. В MATLAB 7 появилась возможность сохранить ту или иную конфигурацию окон на экране, воспользовавшись командой Save Layout (Сохранить разметку). Файлы, в которых запоминались те или иные конфигурации, могут
Пошаговые вычисления в командном окне 17 иметь произвольные имена. Дпя выбора нужной конфигурации, т. е. одного из ранее сохраненных файлов, необходимо прибегнуть к команде Organize Layouts (Организовать разметку). Desktop * Undock Command Window Desktop-Layout ►- Save Layout... Organize Layouts... v Command Window * Command History * Current Directory •• Workspace Help. Profiler v Toolbar * Shortcuts Toolbar •'Titles Default Command Window. Only History and Command Window All Tabbed Рис. 2.4. Команды меню Desktop #JtMATLAB File Edit Debug Desktop Window Help 0 & 1 Ъ Чй Oil «■■> '~Л 1 7? ^ ':? \ Current Director)»;. | KWIATLArWwork 1Command Window НПО djs » s=sin(0.5) ; » c=cos(0.5); » s*s+c*c ans = 1 » Command Window 1 Command History | Current Directory | Workspace | Help | Profiler | •Ф Start | Рис. 2.5. Конфигурация всех окон с вкладками Следующая группа команд (Command Window (Окно команд), Command History (История команд), Current Dictionary (Текущий каталог), Workspace (Рабочее пространство), Help (Справка), Profiler (Профайлер)) позволяет из меню установить комбинацию окон, которые должны присутствовать на экране. Включение или отмена галочки у соответствующей строки меню управляет появлением или исчезновением того или иного окна.
18 Глава 2 Команды последней группы управляют видимостью панели инструментов (Toolbar), заголовков окон (Titles). С помощью команды Shortcuts Toolbar (Пользовательская панель) можно создавать пользовательские панели инструментов. На панель инструментов вынесены наиболее употребительные команды главного меню (рис. 2.6). Только три из них дополняют главное меню. Кнопка Simulink обеспечивает вызов самого популярного расширения пакета MATLAB — системы имитационного моделирования. Кнопка GUIDE вызывает конструктор интерфейса, с помощью которого в диалоговом режиме формируется интерфейс приложения. В правой части панели расположены две кнопки, обеспечивающие просмотр каталогов (Browse for Folder) и перс- ход по каталогам на один уровень вверх (Go up one level). Undo Redo ■vt MATLAB File Edit Debug i»e top Window Help D e£' J г Ln ' 6 i- ш «•> ■■- Lpaste -Copy Lent - Open file ewh rt-Fi e | H ^ I '5* ' Current Directory | H:\MATLAB7\work jj J £] l-Help Browse for folder -I L-GUlDE Go up one level -I - Simulink Рис. 2.6. Кнопки быстрого запуска команд меню На панель окна Workspace (Рабочее пространство) тоже вынесено несколько кнопок (рис. 2.7), ускоряющих выполнение некоторых операций по сохранению и восстановлению переменных рабочего пространства, по очистке рабочего пространства и снятию окна с якоря. Command Window (Окно команд) превращает MATLAB в великолепный калькулятор практически с неограниченной памятью. Для того чтобы многочисленные окна пакета не загромождали экран, можно выполнить команду Desktop | Command Window Only (Рабочий стол | Только окно команд). В левом верхнем углу командного окна находятся два знака », символизирующие начало текущей строки. В этой строке можно набирать формулы или команды, удовлетворяющие синтаксису языка MATLAB и завершающиеся нажатием клавиши <Enter>. Длинные команды, не помещающиеся целиком в одной строке, можно продолжать в одной или нескольких еле-
Пошаговые вычисления в командном окне 19 дующих, используя условный знак переноса в виде трех подряд идущих точек (...). Вслед за знаком переноса необходимо нажимать клавишу <Enter>. (— New variable г- Open selection Г Delete Workspace i Й ® is # 'h | W, - '■ aadcfTrrr] Lpnnt L i -Print •- Plot selection •— Save Undock Workspace -> ■ Load data file Рис. 2.7. Панель кнопок в окне Workspace Если все операнды формулы известны, то MATLAB вычисляет значение выражения, помещая его в системную переменную с именем ans (от англ. answer— ответ): » 2*2 ans = Если в выражении указан операнд, значение которого неизвестно, MATLAB выдает сообщение об ошибке: » (х--1)*(х+1) ??? Undefined function or variable 'x'. Точка с запятой, завершающая набор командной строки, подавляет автоматический режим вывода результата вычислений. Это позволяет производить многошаговые вычисления, сохраняя промежуточные результаты в соответствующих переменных: » s=sin(0.5); » c=cos(0.5); » s.*s+c*c ans = 1 Если формула для вычислений, располагаемая в правой части оператора присваивания, достаточно длинная, то ее часть может быть перенесена на следующую строку. Признаком завершения строки, у которой имеется про-
20 Глава 2 должсние в следующей строке, являются три подряд идущих точки. Все, что располагается в этой же строке правее знака переноса, MATLAB 7 воспринимает как комментарий: » x=sin{0.2)*cos(0.5)+ sin(0.5)*cos(0.2)...формула будет продолжена +cos(0.2)*cos(0.5)-sin(0.2)*sin(0.5) £ продолжение предыдущей строки х = i.40'91 2.2. Переменные рабочего пространства Значения всех промежуточных переменных, использованные в многошаговых вычислениях, MATLAB запоминает в рабочем пространстве (Workspace). На выбор имен переменных накладываются примерно такие же ограничения, как и в других системах программирования: П можно использовать латинские буквы, цифры и символ подчеркивания; П большие и малые буквы в именах различаются; П имя должно начинаться с буквы; П длина имени не должна превышать 63 символов. Информацию о переменных рабочего пространства можно получить, набрав команду who или whos. Первая из них выводит только список имен переменных, а вторая сообщает более подробную информацию об именах переменных (Name), их размерности (size), количестве занятых байтов в оперативной памяти (Bytes) и Классе обьсктов. представляющих соответствующий тип данных (class): » whos Name- Size Bytes Class ans lxl 8 double array с lxl 8 double array s lxl 8 double array Grand total is 3 elements using 24 bytes Детали этой информации будут рассмотрены немного позже. Если мы собираемся продолжить сеанс общения с MATLAB в другой раз, то имена и значения переменных рабочего пространства можно запомнить в файле, прибегнув к услугам команды главного меню File | Save Workspace As (Файл | Сохранить рабочее пространство как) либо набрав аналогичную команду в текущей строке: » save qq
Пошаговые вычисления в командном окне 21 MATLAB добавит к имени нашего файла расширение mat и запомнит все переменные и их значения в файле qq.mat. В начале следующего сеанса достаточно выполнить команду load: »load qq За время сеанса в рабочем пространстве может оказаться довольно много уже использованных переменных. Они занимают оперативную память и замедляют работу системы. Поэтому время от времени рабочее пространство стоит чистить, либо удаляя все переменные, либо только те, которые в дальнейшем не понадобятся. Команда clear без параметров удаляет все переменные рабочего пространства, не задавая никаких вопросов. Однако, будучи набрана с указанием списка имен, удаляет из рабочего пространства только заданные переменные (пример 2.1). ; Пример 2.1. Команда clear * , *•-, ■ * -* -, 'у^ > ■» ш \ v„j » х=1; » у=2; » z=3; » whos Name Size Bytes Class x 1x1 8 double array у lxl 8 double array z lxl 8 double array Grand total is 3 elements using 24 bytes >> clear x у » whos Name Size Bytes Class z lxl 8 double array Grand total is 1 elements using 8 bytes При выполнении команды clear возможна ошибка, не замечаемая системой, — если список имен удаляемых переменных задан через запятые, то будет удалена только первая переменная списка (пример 2.2). Содержимое остальных переменных списка будет отображено, если список не заканчивается точкой с запятой. ! Пример 2.2 Команда clear (продолжение) ^ ■^pt-'-^fh-^ ^"i" V0&* *..~vj ■» х=1; i ■» y=2;
22 Глава 2 » z=3; » clear x,y, z У = whps Name У z Size lxl lxl Bytes Class 8 double array 8 double array Grand total is 2 elements using 16 bytes Полную очистку рабочего пространства можно выполнить и командой Clear Workspace (Очистить рабочее пространство) из меню Edit (Правка). Правда, в этом случае система потребует подтвердить запрос на удаление (рис. 2.8). •^MATLAB Q /|\ Are ypu sure you want to clear your workspace? No I Yes Рис. 2.8. Запрос подтверждения на очистку рабочего пространства 2.3. Скаляры или массивы? Индексированные переменные Своим названием пакет MATLAB обязан сокращению от английского названия Matrix Laboratory — дословно "матричная лаборатория". Поэтому можно догадаться, что основным видом данных, которые используются в пакете, являются матрицы. Даже общепринятые скалярные переменные MATLAB рассматривает как матрицы размерности lxl1. До поры до времени на скалярных переменных пользователь эту специфику не чувствует, т. к. 1 Традиционно в математической литературе обозначение 1x1 (или, в общем случае, тхп) соответствует размеру матрицы, а размерность при этом равна 2. Однако в этом издании указанное обозначение трактуется в понимании авторов. — Ред.
Пошаговые вычисления в командном окне 23 для единственного элемента массива размерности 1x1 указывать индексы не обязательно: » х=2 .х = 2 Однако никто не мешает обратиться к единственному элементу массива с двумя и даже с одним индексом, задавая его в круглых скобках: » х(1,1) ans = 2 » х(1) .ans = 2 Последнее требует объяснения. Дело в том, что вместо обычных индексов, принятых в математике и апгоритмйческих языках, в компиляторах используют так называемые приведенные индексы, определяющие позицию соответствующего элемента массива в оперативной памяти. Так как- оперативная память использует линейную адресацию своих ячеек, то для одномерного массива приведенный индекс совпадает с обычным. Для двумерного массива а с количеством элементов mxn (т — число строк, п — число столбцов) приведенный индекс к элемента Ai#j зависит от способа распределения элементов в памяти. MATLAB по аналогии с Fortran использует отсчет индексов в массивах от 1 и располагает элементы матрицы по столбцам. Поэтому элементу a-i,j в памяти предшествуют (j-1) столбцов по m элементов в каждом, и этот элемент расположен на месте с номером k=(j-i) *m+i. MATLAB, наряду с традиционными индексами в многомерных массивах, позволяет пользоваться и единственным приведенным индексом, что несколько повышает скорость вычислений. Попытка обратиться к несуществующему элементу массива приведет к выдаче сообщения об ошибке: » х(2) ?'?? Index exceeds matrix dimensions . Векторы и матрицы в MATLAB могут быть не только числовыми, но и символьными (пример 2.3). Однако при формировании строковых матриц следует задавать значения равной длины для всех элементов массива, дополняя при этом более короткие строки недостающими пробелами в конце. 2 Зак. SW
24 • Глава 2 ; Пример 2.3. Символьные векторы и матрицы. .'$? ?у. -4¾¾¾ J; .• -.,/-^1^1¾¾¾ » а=[ 'abcdefghijk'; 'ABCDEFGHIJK' ,-42345678904 ??? Error using ==> vertcat All tows, in the bracketed expression must have the same number of columns. » a=['abcdefghijk'; 'ABCDEFGHIJK'; "1234567890 '] a = abcdefghijk ABCDEFGHIJK 1234567S90 » whos Name Size Bytes Class a 3x11 66 char array Grand total is 33 elements using 66 bytes Попытка разделить строковые значения пробелами или запятыми приведет к конкатенации этих строк, т. е. к созданию символьного вектора-строки: » b=['ABCDEF" '12345'] b = ABCDEF12345 » whos Name Size Bytes Class b lxll 22 char array Grand total is 11 elements using 22 bytes Как и в других алгоритмических языках, в MATLAB допускается существование пустых массивов, не содержащих ни одного элемента (пример 2.4). ! Пример 2.4. Задание пустых массивов • .'.. V \j&.K- ~v? ^ ■ Г. !Г. " .'.„.'..■.■....л.-...-.'::-..-..-.-:,..-:;...-..: ::.-;.„^,;;.яйЕ,...,...;....:..ла. ;..;:.:; » а=[] а = [] » b=ehar([]) Ь = 1 1 » c=uint8([]) с = []
Пошаговые вычисления в командном окне 25 > whos Name а. Ь с Size 0x0 0x0 0x0 Bytes 0 0 0 Class double array char array uint8 array Grand total is 0 elements using 0 bytes Пустыми массивами считаются и такие, у которых максимальное значение любого индекса равно нулю. 2.4. Выбор формата отображения числовых данных Числовые данные, с которыми оперирует MATLAB на IBM-совместимом ПК, в памяти компьютера представлены вещественными или комплексными значениями в формате double. Это означает, что каждое вещественное число занимает 8 байтов в оперативной памяти и принимает по модулю значения из диапазона |10~308, 10+308]. Количество значащих десятичных цифр при этом достигает 16—17. Комплексное число, представленное действительной и мнимой частями в таком же формате, занимает, соответственно, 16 байтов. Именно с такой точностью MATLAB выполняет все вычисления. Однако при отображении числовых результатов на дисплее часть значащих цифр отбрасывается в соответствии с установленным форматом вывода. Обычно числа выводятся с небольшим количеством значащих цифр. Целые — не более чем с 9 цифрами, вещественные с фиксированной запятой — не более чем с 4 цифрами в дробной части, очень большие или очень маленькие числа — в формате с плавающей запятой и пятью значащими цифрами. Отображаемые значения округляются по общепринятым в математике правилам (табл. 2.1). Таблица 2.1 Пример отображения числа » .4=123456789 х = ; 123456789 | » х=1234567890 ! х = ! 1.2346е+009 Пример отображения числа » х=10/б х = 1.6667 » х=100/6 х = 16.6667 Пример отображения числа » х=1/100.0 ; х = 0.0010 » х=1/10000 х = 1.0000е-004
26 Глава 2 Таблица 2.1 (окончание) Пример отображения числа » х=1/60 X = ; 0.0167 » Х = 1/б ; X = 1 0.1667 1 Пример отображения 1 числа ; » х-1000/6 1 х = ; 166.6667 | » х=10000/6 : х = I 1.6667е+003 j Пример отображения 1 числа I » к=123.456789 j х = '; 123.4568 1 » .4=1234.5678 9 1 х = I 1.2346е+003 По умолчанию система использует формат, обозначаемый служебным словом short (укороченный)- Однако формат вывода числовых данных может быть и другим (табл. 2.2). Таблица 2.2 Пример отображения числа » format short ; » x=sqrt(2) х = j 1.4142 г » format long j » X j X = j 1.41421356237310 » format rational » X : X = i ..393/985 i Пример отображения числа | » format short e ; j » x j : X = | j 1.4142e+000 j j » format long e j j » X j I x = ! j 1.414213S6237309Se+000 j В табл. 2.2 использованы основные форматы вывода числовых данных с фиксированной и плавающей запятой. Последний формат позволяет отображать числовые значения в виде подходящих рациональных дробей с минимально возможными числителями и знаменателями. Следует заметить, что значение переменной х не зависит от установленного формата вывода. Формат вывода результатов вычислений может быть установлен как программным путем (именно это и продемонстрировано в табл. 2.2), так и с помощью изменения параметров Command Window (Окно команд). Для этого следует войти в меню File (Файл), выбрать команду Preferences (Пред-
Пошаговые вычисления в командном окне 27 почтения) и в раскрывшемся диалоговом окне выделить пункт Command Window (Окно команд) — рис. 2.9. tjk Preferences EGeneral l+l-Fonts — Colors ■—Keyboard & Indenting |—Command History rT~Edilor/Debugger ■ Help -Web Current Directory —Workspace Array Editor GUIDE Г+Vfigure Copy Template Command Window Preferences Text display ■■ ■*■ ■ Numeric format: | short T | Numeric display: Display —; ~ Г" Wrap lines П Llmi matrix cS: Number or lines i bank long short e longe short g longg - hex rational eighty columns ndow scroll buffer: | 5 OOQ-H Accessibility P Arrow keys navigate Instead of recalling history OK Cancel Apply Help Рис. 2.9. Выбор формата для вывода числовых данных в командном окне Форматы short g и long g представляют собой гибрид между соответствующими форматами вывода с фиксированной и плавающей запятой. В зависимости от отображаемого значения они выбирают то или иное представление числа (пример 2.5). [Пример 2.5. ФорЙат short -." Т^- '":"?l'gS№""?V!-! » format short g » x=sqrt(2) x = 1.4142 » x=sqrt(2000000) x = 1414.2
28 Глава 2 » x=sqrt(2е+20) х = 1. .1.1.426-1 010 Формат bank позволяет оперировать с финансами, сохраняя в дробной части числа два знака, соответствующие мелким денежным единицам: » format bank » х=1000 х = 1000.00 Формат + обеспечивает вывод только знаков чисел, сами значения при этом не выводятся: » format + » х=[-1 2 -3 4 -5]; » х X = Формат hex обеспечивает вывод числовых данных в шестнадцатеричном формате: » format hex » х=1 X = 3fi0000000000000 Согласитесь, что наблюдать вещественные данные в шестнадцатеричном формате во многих случаях смысла не имеет. Эта система счисления хороша только для целочисленных форматов компьютерных чисел. В языке MATLAB существуют и другие возможности по изменению формата выводимых данных. Они построены на базе функции sprintf, хорошо известной программистам по языку С. С этими возможностями мы познакомимся позже. Для выделения результата вычислений или значения переменной MATLAB вставляет пустую строку перед выводимым значением. В приводившихся выше примерах с целью экономии места эта пустая строка удалялась вручную. Однако ее отсутствие в командном окне тоже может оказаться полезным, т. к. позволит разместить на экране большее количество результативных строк. Такой режим вывода обеспечивается установкой параметра Numeric display = compact в соответствующем раскрывающемся списке окна Preferences (Предпочтения) в разделе Command Windows (Окно команд) — см. рис. 2.9. Возврат в режим разреженного вывода происходит после установки Numeric display = loose.
Пошаговые вычисления в командном окне 29 2.5. Арифметические выражения Основу большинства расчетов составляют вычисления значений арифметических выражений, в которых в качестве операндов могут выступать константы, переменные, стандартные и нестандартные функции. Специфика MATLAB заключается в том, что, в отличие от большинства алгоритмических языков, здесь допускается использование операндов-массивов. А это означает, что в результате вычисления выражения может получиться некоторое множество значений — вектор, матрица или массив большей размерности. 2.5.1. Некоторые свойства вещественных данных В отличие от большинства алгоритмических языков, MATLAB довольно спокойно реагирует на переполнение разрядной сетки. Он выдает предупреждение, например, о делении на 0, но предлагает в качестве результата внутреннее представление самого большого (inf = 1.8е+зо&) или самого маленького (-inf = -i.8e+308) вещественного числа, допустимого в формате double: » х=1/0 Warning: Divide by zero. x = Inf » y=-l/0 Warning: Divide by zero. У = -Inf Когда вычисление степенной функции, например, экспоненты, приводит к переполнению, то в качестве результата возвращается "машинная бесконечность", но сообщение о переполнении уже не выдается: » w=exp(710) w = Inf А в тех случаях, когда математический результат не определен, например, при делении 0 на 0, в соответствующую переменную засылается специальный признак NaN (от англ. Not a Number— "не число"): » z=0/0 Warning: Divide by zero. z = NaN
30 Глава 2 Дальнейшее использование неопределенного операнда в последующих вычислениях будет приводить также к неопределенному результату: » x=z+l NaN Среди полезных системных числовых переменных и констант отметим (пример 2.6): □ eps — относительную погрешность при вычислениях с плавающей запятой; П reaimax — наибольшее положительное число с плавающей запятой; П reaimin — наименьшее положительное число с плавающей запятой; П pi — число %. I Пример 2.6. Отображение значений системных переменных и констант "\ » eps ans = 2.220446049250313е-01б » reaimin arts = 2 .225073858507201е-308 >> reaimax ans = 1.7976.93134862316e+308 » pi ans = 3.14159265358979 Изменение системной переменной eps оказывает влияние на точность вычисления значений некоторых математических функций. Однако другие функции на эту переменную не реагируют и продолжают вычисления с минимально допустимой погрешностью. 2.5.2. Специфика использования комплексных величин Запись комплексных величин, используемых в формулах, напоминает общепринятые математические стандарты.
Пошаговые вычисления в командном окне 31 Мнимые части комплексных чисел сопровождаются либо буквой i, либо буквой j: » х=1.5-0.51 х = 1.5000 - O.SOOOi » y=1.5-0.5j У = 1.5000 - 0.5000i Если "переменным" i или j не присвоены какие-либо значения, то их можно применять для формирования комплексных данных, используя знак умножения и располагая такой "сомножитель" до или после мнимой части: » а=1; » x=i*а х = 0 + l.OOOOi » y=(i) *а; » У У = О + l.OOOOi » z=a*i z = 0 + l.OOOOi Однако если i или j представляют настоящие переменные, которым уже присвоены какие-либо значения, то их использование в подобных выражениях не приводит к появлению комплексных данных: » i=l i = 1 » x=i*a х — 1 Когда полные комплексные числа используются в операциях умножения, деления или возведения в степень, то для устранения неоднозначности их заключают в круглые скобки: » z=(1.5-0.5i)*(2.5+0..8'j) .? = 4.1500 - O.OSOOi
32 Глава 2 С помощью стандартных функций real и imag можно выделить вещественную и мнимую части комплексного значения: » real(z) ans- = 4.1500 » imag(z) ans = -0.0500 Функция complex позволяет сконструировать комплексное значение по паре вещественных чисел: » complex(1,-1) ans = 1.0000 - l.'OOOOi Функцией conj можно воспользоваться для получения комплексного сопряженного числа: » conj(z) ans = 4.1500 + 0.05001 Такого же результата можно добиться, располагая апостроф вслед за комплексным значением: » x=4.15+0.05i' х = 4.1500 - 0..05001 » у=х' У = 4.1500" + 0.05001 Математики довольно часто используют и другие формы представления комплексных чисел: z = х + i ■ у = р • е1ч> = р (cos ф + i • зin (р). Здесь р — модуль комплексного числа (р2 = хг+у2), а ф — угол наклона радиус-вектора, проведенного из начала координат в точку (х,у)- Значения этих параметров можно определить с помощью стандартных функций abs и angle (величина угла выдается в радианах). Над комплексными данными определены все арифметические операции — сложение, вычитание, умножение, деление, возведение в степень. Комплексные операнды и выражения могут выступать в качестве аргументов стандартных функций. Одним словом, в пакете MATLAB реализовано все, с чем нас знакомили в курсе "Теория функций комплексных переменных".
Пошаговые вычисления в командном окне 33 2.5.3. Числовые матрицы и векторы, специфика представления Решение систем линейных алгебраических уравнений — одна из математических задач, в которой мы встречаемся с векторами и квадратными матрицами: aiiXi + ai2x2 + апх-з = Ьх; ajiX]. + а»;Хг + агзХз = Ьг; (2.1) a^LXi + азгХз + а3зх3 = Ь3. Если обозначить матрицу коэффициентов через а, вектор-столбец неизвестных — через х, а вектор-столбец правых частей — через в, то система (2.1) в векторной форме имеет вид: а*х = в. (2.2) В матричной же форме решение системы (2.2) получается умножением обеих частей равенства на обратную матрицу а"1: х = а_1*в. (2.3) Для задания значений компонентов вектора-строки (т. е. элементов матрицы размерности 1хл) используются квадратные скобки, в которых числовые данные отделяются друг от друга пробелами или запятыми: » у=[1 2 3] У = 12 3 » у=[<5,5,6] У = 4 5 6 » Количество пробелов, которое MATLAB вставляет при выводе компонент вектора-строки, регулируется параметром Tab size (Табуляция) (см. окно Preferences | Command Window | Keyboard & Indenting (Предпочтения | Окно команд | Клавиатура и Отступы)). По умолчанию оно равно 4. Для задания значений компонентов вектора-столбца (т. е. элементов матрицы размерности лх1) используется тот же прием, но в качестве разделителей данных выступают точки с запятыми: » Ь=[1; 4; 2] Ь = 1 4 2
34 Глава 2 Комбинируя оба варианта разделителей, можно сформировать двумерный массив коэффициентов: » а=[1 -1 1; 2 0 2; 0 1 Д.] а = 1-11 2 0 2 0 11 Формула (2.3) позволяет найти решение системы, написав всего одну строку, воспользовавшись стандартной функцией обращения квадратной матрицы (пример 2.7). | Пример 2.7.Решение системы линейных уравнений; « "~ .-■ '■•-'■"-",..". ■» ■" *?*...[ » x=inv(a) х = 1 1 1 » whos "Name а b X *Ь Size З.чЗ 3x1 3x1 Bytes 72. ■24 ?4 Class double double double array array array Grand total is 15 elements using 120 bytes Как и в других алгоритмических языках, к элементам матриц и векторов обращаются, используя индексы. В отличие от языка С, в системе MATLAB индексы отсчитываются от 1 и заключаются в круглые скобки — х(1), а{2,3). Довольно интересной особенностью языка MATLAB является возможность выполнения однотипных операций над подмножеством компонентов векторов или матриц. Для этого вместо индекса указывается диапазон индексов, разделяемых двоеточием: » z(2:5)=3 MATLAB предлагает разнообразные средства для создания типовых матриц. Функции zeros и ones используются для заполнения квадратных или прямоугольных матриц нулями или единицами соответственно. С помощью
Пошаговые вычисления в командном окне 35 функции eye формируется единичная квадратная или прямоугольная матрица. Заполнение элементов матриц случайными числами с равномерным или нормальным распределением обеспечивают функции rand и randn. В состав пакета входят и специализированные функции, позволяющие создавать магические квадраты и матрицы, названные именами известных математиков — Адамара, Гильберта, Паскаля, Уилкинсона, Ханкеля. Пример 2.8 демонстрирует несколько простейших вариантов заполнения матриц. ! Пример! 2v8l Формирование » a=zeros(5) а = 6 0 0 0 0 0 0 0 0 0 » b=zeros.(3, Ь = 0 0 0 0 0 с » c=ones([2 с = 1 1 1 1 » d=eye(4) d = 1 0 0 1 0 0 0 0 » e=ra.nd (4) е — 0.9501 0.2311 0.6068 0.4860 » f=randn(4) 4) 3]) 0. 0. 0 0 0 0 0 0 0 0 0 0 1 д. 0 0 1 0 8913 7621 4565 0185 0 0 0 0 0 0 0 0 0 0 0 1 0 ■О 0 0 ТИПОВЫХ Mi 0 0 0 0 0 8214 0 4447 0 6154 0 7919 0 атриц 9218 7382 1763 4 057
36 Глава 2 -0.4326 -1.6656 0.1253 0.2877 -1.1465 1.1909 1.1892 -0.0376 0.3273 0.1746 -0.1867 0.7258 -0.5883 2.1832 -0.1364 0.1139 Ранее сформированные массивы могут участвовать в конструировании новых массивов в качестве их клеток (пример 2.9). Пример 2.9. Объединение матриц по вертикали ^ш*шт » g=[e;f] Я = 0.9501 0.2311 0.6068 0.4860 -0.4326 -1.6656 0.1253 0.2877 0.8913- 0.7621 0.4565 0.0185 -1.1465 1.1909 1.1892 -0.0376 0.8214 0.4447 0.6154 0.7919 0.3273 0.1746 -0.1867 0.7258 0.9218 0.7382 0.1763 0.4057 -0.5883 2.1832 -0.1364 0.1139 Еше больше возможностей по формированию блочно-диагональных матриц предоставляет функция bikdiag. В отличие от большинства систем программирования на базе других алгоритмических языков, MATLAB хранит матрицы в оперативной памяти по столбцам. Такой способ в свое время использовали все трансляторы с языка Fortran. Очень важной особенностью практически всех функций MATLAB является возможность обработки аргументов, заданных векторами (пример 2.10). А значения компонентов вектора, образованные но закону арифметической прогрессии, формируются примерно так же, как и параметры цикла типа for (начальное значение: шаг: конечное значение). Пример 2.10. Использование векторных аргументов » х=[0:0.2:1] х = 0 0.2000 » y=sin<x) 0.4000 0.6000 0.8000 1.0000
Пошаговые вычисления в командном окне 37 О 0.1987 0.3894 0.5646 0.7174 0.8415 Такого рода приемы часто используются при подготовке табличных значений функций, необходимых для построения графиков. 2.5.4. Специфика выполнения арифметических и логических операций При составлении алгебраических выражений MATLAB разрешает использование традиционных знаков арифметических операций и символов специальных операций, список которых приведен в табл. 2.3. Таблица 2.3 Символы Выполняемое действие Операции над числовыми величинами + Покомпонентное сложение числовых массивов одинаковой размерности; добавление скалярной величины к каждому элементу массива Операции над числовыми величинами Покомпонентное вычитание числовых массивов одинаковой размерности; вычитание скалярной величины из каждого элемента массива * Умножение матриц в соответствии с правилами линейной алгебры (число столбцов первого сомножителя должно быть равно числу строк второго сомножителя); умножение всех компонентов массива на скаляр - * Покомпонентное умножение элементов массивов одинаковой размерности / Деление скаляра на скаляр; покомпонентное деление всех элементов массива на скаляр: А/В = А*В'1 = А * inv<B) (а, в — квадратные матрицы одного порядка) • / Покомпонентное деление элементов массивов одинаковой размерности \ " А\в = А"'*в —левое матричное деление (а—квадратная матрица) А А. \в — покомпонентное деление элементов в на а (левое поэлементное деление) " Возведение скаляра в любую степень; вычисление целой степени квадратной матрицы ' Вычисление сопряженной матрицы - ' Транспонирование матрицы
38 Глава 2 Таблица 2.3 (окончание) Символы Выполняемое действие Логические операции б Логическое умножение скаляров; логическое покомпонентное умножение массивов одинаковой размерности; логическое умножение массива на скаляр I Логическое сложение скаляров; логическое покомпонентное сложение массивов одинаковой размерности; логическое сложение массива со скаляром Логическое отрицание скаляра или всех элементов массива Операции отношения Проверка на равенство ~= Проверка на неравенство > Проверка на "больше" >= Проверка на "больше или равно" < Проверка на "меньше" <= Проверка на "меньше или равно" Но даже такие традиционные операции, как сложение, в выражениях MATLAB выполняются особым способом. Самым привычным является сложение скалярных величин (т. е. массивов размерности 1x1), соответствующее аналогичному действию в большинстве алгоритмических языков. Если обоими операндами являются массивы одинаковой размерности, то осуществляется покомпонентное сложение элементов с одинаковыми индексами. Такой подход в свое время применялся в ранних версиях Basic, включавшего операторы типа мат а=в+с. Однако если в MATLAB к массиву любой размерности добавляется скалярная величина, то она добавляется к каждому элементу массива. По сути дела, добавляемое скалярное значение преобразуется в массив такой же размерности, что и первое слагаемое (аналог приведения типов в выражениях с разнокалиберными операндами), и каждый элемент расширенного массива равен этому значению. Попытку сложить массивы разной размерности (за исключением случая, когда один из операндов — массив 1x1) система пресекает с выдачей соответствующего сообщения об ошибке. Аналогичное приведение типов выполняется для большинства операций, когда одним из операндов является массив, а вторым — скаляр.
Пошаговые вычисления в командном окне 39 Впервые знак операции возведения в степень в виде х**у появился в Fortran (1954 г.)- Вертикальная стрелка Т как знак возведения в степень был предложен спустя несколько лет в проекте языка Algol 58. Символ Л для этой же цели взял на вооружение Basic, откуда он и перекочевал в MATLAB. К сожалению, ни С, ни Pascal не включили аналогичную операцию в набор элементарных действий (здесь приходится прибегать к услугам библиотечной функции pow). Кроме знаков логических операций, приведенных в табл. 2.3, можно использовать системные функции and(x,у), ог(х,у), хог(х,у) И not(x). При выполнении логических операций над числами действует соглашение, принятое в С, — ненулевые значения рассматриваются как истина, а нулевые как ложь. Если операндами логической формулы являются массивы, то операция производится над элементами с одинаковыми индексами. Результатом такой операции является массив такой же размерности, что и операнды, заполненный нулями и единицами в зависимости от исхода поэлементного действия. Аналогичный результат формируется при сравнении матричных операндов (пример 2.1J). ! Пример 2.11, Сравнение, матричных отера^ » a=[I 2 3; 4 5 6] а = 12 3 4 5 6 » Ь=[2 2 2; 5 5 5] b = 2 2 2 5 5 5 i» с=а >=b с = Oil Oil 2.5.5. Использование элементарных математических функций В ряде приводившихся выше примеров мы использовапи элементарные математические функции типа sin(x), cos(x), sqrt(x) и др. В этом разделе систематизированы библиотечные функции (табл. 2.4), которые доступны пользователю MATLAB. Обозначения многих функций MATLAB совпадают
40 Глава 2 с названиями аналогичных функций в других атгоритмических языках, поэтому их назначение в особых комментариях не нуждается. Однако еще раз напомним, что аргументом большинства математических функций могут быть комплексные данные и числовые массивы. Таблица 2.4 Категория функций Наименования функций Тригонометрические, аргумент в радианах Тригонометрические, аргумент в градусах Обратные тригонометрические, результат в радианах Обратные тригонометрические, результат в градусах Гиперболические Обратные гиперболические Степени, логарифмы, корни Округления Наибольший общий делитель Наименьшее общее кратное Модуль числа Знак числа Остаток от деления с учетом знака делимого Остаток от деления Разложение числа на простые множители Вычисление факториала Дробно-рациональная аппроксимация вещественного числа Генерация простых чисел, не превосходящих аргумента cos, cot, csc, sec, sin, tan cos.d, cotd, cscd, seed, sind, tand acos, acot, acsc, asec, asin, atan, atan2 acosd, acotd, acscd, asecd, asind, atand cosh, coth, csch, seen, sinh, tanh acosh, acoth, acsch, asech, asin'n, atanh exp, expml, log, loglp, log2, log.1.0, nextpow2, pow2, feallog, realsqrt, sqrt ceil, fix, floor, round gcd lem abs sign mod rem factor factorial rats primes В некотором уточнении нуждаются функции округления, их немного больше, чем в С. Функция round, отсутствующая в С (но существующая в
Пошаговые вычисления в командном окне 41 Pascal), производит округление по математическим правилам. О функции ceil говорят, что она округляет в сторону +~ (точнее, до ближайшего большего числа). В отличие от нее, функция floor округляет в сторону -« (точнее, до ближайшего меньшего числа). Функция fix просто отбрасывает дробную часть. Результаты работы функций округления приведены в табл. 2.5. Таблица 2.5 i Результат работы I функции | ceil(l.l) = 2 ; ceil(-l.l) = -1 ; fix(l.l) = 1 | fix(-1.1) = -1 | floor(1.1) = 1 1 floor(-1.1) = -2 | round(l.l) = 1 ( round(-1.1) = -1 j Результат работы i функции ! ceil(l.S) = 2 | ceil(-1.5) =■ -1 | fix(1.5) = 1 ; fix(-1.5) = -1 j floor(1.5) = 1 ! floor(-1.5) ■■ 2 ! round(1.5) = 2 | round(-1.5) = -2 j Результат работы ! функции j ceil(1.8) = 2 ! | ceil(-1.8) = -1 j j fix(1.8) = 1 j j fix(-1.8) = -1 | | floor(1.8) = 1 j | floor(-l.B) = -2 j j round (1.8) = 2 j | round (-1.8) = -2 j Для функций gcd (от англ. greatest common divisor — наибольший общий делитель) и icm (от англ. least common multiple — наименьшее общее кратное) приведем очевидные результаты их работы: gcd(100,25) = 25 Icm (100,25) = 100 Функции, вычисляющие остаток от деления, обычно применяются к целым числам (хотя и представленным в формате double). Результаты их работы проще понять на примерах, приведенных в табл. 2.6. Таблица 2.6 I Результат ра- I Результат работы i Результат работы 1 Результат работы : боты функции I функции I функции j функции !mod(7,5)=2 | mod (-7,5) = 3 !mpd(7,-5) =-3 I mod (-7,-5) =-2 ! у i | i -i ! rem(7,5)= 2 j rem(-7,5) = -2 j rem(7,-5) = 2 I rem(-7,-5) = -2 I
42 Глава 2 Функция sign (знак) принимает одно из трех значений: -1 (если аргумент отрицателен), о (если аргумент равен 0) и +1 (если аргумент положителен). В MATLAB 7 появилась группа прямых и обратных тригонометрических функций, работающих с углами в градусах. Наряду с хорошо знакомыми программистам функциями ехр(х), iog(x) и sqrt(x) в системе MATLAB представлены некоторые их разновидности: П функция expmi(x) вычисляет значение expix-i); П функция logip(x) вычисляет значение ieg(x+u; П функция pow2 (х) возводит 2 в степень х; П функция nextpow2(x) определяет наименьшую степень двух, ограничивающую х сверху (nextpow2 (1000)=10). Такая функция полезна при работе с быстрыми преобразованиями Фурье. Функции reailog и reaisqrt вычисляют, соответственно, натуральный логарифм и корень квадратный для каждого элемента матрицы: » х=[1 2 4 8]; » reallog(x) ans = 0 0.693.1 1.3863 2.0794 » reaisqrt(х) .ans = 1.0000 1.4142 2.0000 2.8284 С помощью функции primes можно сгенерировать последовательность простых чисел: » primes(25) ans = 2 3 5 7 11 13 17 19 23 Функции perms и nchoosek позволяют генерировать перестановки и сочетания из заданных элементов: » perms([1 2 4]} ans = 4 4 2 2 1 1 ;hoc 2 1 1 2 4 1 1 4 2 4 4 2 >sek(['A' "В"
Пошаговые вычисления в командном окне 43 ans = АВ АС ВС Следует заметить, что список функций, приведенных в этом разделе, составляет крохотную часть от набора библиотечных функций, встроенных в ядро MATLAB. Об этом можно судить по объему документации, посвященной описанию функций. Она представлена в виде трех файлов — refbook.pdf, refbook2.pdf и refbook3.pdf. Их общий объем превышает 15 Мбайт, а в печатном виде документ занимает порядка 2000 страниц, на которых приведены достаточно подробные сведения примерно о 850 функциях и командах с примерами их использования, графиками и таблицами. 2.6. Построение графиков функций одной переменной Одним из способов визуализации результатов вычислений является построение графиков различных функций. MATLAB предоставляет пользователям достаточно гибкие средства построения и редактирования графиков плоских и пространственных кривых, трехмерных поверхностей и некоторых геометрических фигур. Рассмотрим самые простые средства построения графиков и их ручного редактирования с целью включения в состав отчетной документации. Более сложным вопросам машинной графики и соответствующим программным средствам, реализованным в системе MATLAB, посвящена гл. 10. 2.6.1. Простые графики в декартовых координатах Для того чтобы построить график функции y=f(x), достаточно тем или иным способом сформировать два вектора одинаковой размерности — вектор значений аргументов (х) и вектор соответствующих значений функции (у), и обратиться к функции plot (пример 2.12). I. Пример 2.12. Построение графика фун^цйй^э^^^^^рк. ^lMp.1, ^":ftt^ !jl » х=0:0.1:6.28,- » y=sin(x).*ехр(-х); » plot (х, у)
44 Глава 2 В простейшем случае, которым мы воспользовались при вызове функции plot, MATLAB автоматически создает окно'с заголовком Figure 1, размешает в нем стандартное меню и панель инструментов, выделяет в области клиента прямоугольное поле с графиком функции, производит соответствующее масштабирование и разметку по обеим координатам (рис. 2.10). Собственно график функции получен путем соединения смежных точек таблицы отрезками прямых. Чем меньше точек было бы в таблице отображаемой функции, тем заметнее была бы кусочно-линейная структура графика. •J* Figure 1 File Edit View Insert Tools Desktop Window Halp DcSa©ifei.^^f)®|.«;iDS!i3n ' 0.35 0.3 0.25 0.2 0.15 0.1 0.05 0 -0.05 •Л ' I \ 7 \ \ I X 3 12 3 4 5 6 mna ■» ' 1 Рис. 2.10. График затухающей синусоиды на интервале [О, 2л] Если мы обратимся к функции plot повторно, то она создаст новое окно с заголовком Figure 2 и разместит в нем следующий график. Мы могли бы совместить оба графика в одном окне двумя разными способами. В первом случае перед вызовом функции plot мы должны построить таблицы обеих функций, например, (xl,yl) и (>;2,у2). А при вызове функции plot указать их в списке аргументов (пример 2.13). Пример 2.13. Построение двух графиков в одном окне »^*£У" » х1=0:0.2:б.28; ■»■ yl=sin(xl);
Пошаговые вычисления в командном окне 45 » y2=cos(xl); » plot(xl,yl,xl,y2) Результат работы этого фрагмента приведен на рис. 2.11. Ш 0.5 : ■ Й!-> л :.; А5 /\ /\ / / \ Х \ ' v У Рис. 2.11. Совместное отображение графиков двух функций в одном окне Второй способ заключается в блокировании режима создания нового графического окна с помощью функции hold on (дословно — заморозить предыдущее окно) — пример 2.14. | Пример :2.14. Использование функции hold on "*: » plot(xl,yl) » hold on » plot(xl,y2) i-....-.j;;;;;...V....;.j.,.;.rrtii.^*^:V:l..J При выполнении примера 2.14 в командном окне обратите внимание на то, что график второй функции отображен зеленым цветом, тогда как первая кривая имела синий цвет. MATLAB автоматически сменил цвет отображения следующего графика. Однако на выбор цвета того или иного графика может повлиять и пользователь, указав в функции plot дополнительный параметр — символ, ассоциированный с одним из 8 предусмотренных цветов (табл. 2.7): » plot (х, у, 'д')
46 Глава 2 Таблица 2.7 Символ цвета У га с г Цвет графика Желтый (от англ. yellow) Малиновый (от англ. magenta) Циановый (от англ. cyan) Красный (от англ. red) Символ цвета g ь w к Цвет графика Зеленый (от англ. green) Синий (от англ. blue) Белый (от англ. white) Черный (от англ. b/acfc) На вид графика пользователь может дополнительно повлиять, задав стиль линии и форму маркера, которым метятся табличные точки. Стиль линии предусматривает выбор одной из четырех возможностей — сплошная линия (по умолчанию управляющий символ — тире), пунктирная линия (управляющий символ — двоеточие), штрих-пунктирная линия (управляющие символы — тире и точка), штриховая линия (управляющие символы — два тире). Управляющие символы, определяющие стиль линии, задаются в строке третьего параметра вместе с цветом. Порядок следования символов — любой: » plot(x,y.'g:■) или » plot (х, у, ' :д') Тип маркера задается еще одним символом в этой же управляющей строке. Всего таких символов — 13, и соответствующие им маркеры приведены в табл. 2.8. Таблица 2.8 Символ о X + * s шопе Маркер Жирная точка Кружок Косоугольный крестик Прямоугольный крестик Восьмиконечная снежинка Квадратик Отсутствие маркера Символ d V Л < > р h Маркер Ромбик Треугольник вершиной вниз Треугольник вершиной вверх Треугольник вершиной влево Треугольник вершиной вправо Пятиконечная звезда Шестиконечная звезда Если в стилевой строке указан тип маркера, но не задан стиль линии, то табличные точки маркером метятся, но друг с другом отрезками прямых не соединяются (пример 2.15).
Пошаговые вычисления в командном окне 47 [Пример 2.15. Использование маркеров ,. ' . . » х=Ц 2 3 4]; » у=[1 2 2 4]; » plot (х, у, 's—') Соответствующий график с маркерами на штриховой линии привеяен на рис. 2.12. 4 3.5 3 2.5 ■I 2 1.5 1С У3- У 1.5 .2 2.5. 1 / /" " / . / / —сГ 3 3.5 ' \ Рис. 2.12. График с маркерами, стиль линии — штриховой Дополнительные украшения графика заключаются в возможности снабдить его Заголовком (ФУНКЦИЯ title), Подписать ОСИ (фуНКЦИИ xlabel, ylabel), нанести координатную сетку (функция grid on) и разместить легенду (функция legend). Используем все эти возможности на графике синуса и косинуса (пример 2.16, рис. 2.13). ! Пример 2.16. Оформление графиков . ^ ^ ;>•;;„. '>■: J$i » .4=0:0.2:6.28; » yl=sin(х); » y2=cos(х); » plot(x,yl,'-\x,y2, ' .') » legend ('sin','cos',4) » ylabel('y-axis')
48 Глава 2 » xlabel('x-axis') » grid on »' title('Function sin & cos') Рис. 2.13. График функций с подписями, легендой и сеткой Легенда позволяет внести ясность в анализ изображения с несколькими графикам. Третий параметр, в функции legend (на самом деле этот числовой параметр можно написать в любом месте списка) управляет размещением легенды в графическом окне: П -1 — легенда размешается вне поля графика, вверху справа; По — система выбирает лучшее место в поле графика, не перекрываемое данными; П 1 — легенда размешается в правом верхнем углу (по умолчанию — там же); П 2 — легенда размещается в левом верхнем углу поля графика; D з — легенда размещается в правом нижнем углу поля графика; Па — легенда размещается в левом нижнем углу поля графика. В некоторых случаях совмещение двух графиков в общем окне может вызвать проблемы, связанные с тем, что диапазоны изменения аргументов или значений функций не совпадают. Для разрешения этих проблем MATLAB предлагает функцию piotyy, которая производит двойную оцифровку осей (пример 2.17). Для первой функции цифруются ось х внизу, ось у слева, а для второй функции ось х размечается вверху, ось у — справа (рис. 2.14). Цвет оцифровки при этом совпадает с цветом кривых.
Пошаговые вычисления в командном окне 49 Пример 2.17. Двойная оцифровка осей тш*> » х=0:0.1:6.28; » yl=sin(x); » y2=sin(x)+eos(х); » plotyy(x,yl,x,y2) ■- 6.5 0 -0.5- С / \\ V/ . ч У . ] 1 2 3 4 5 6 2 1 0 -i 1 Рис. 2.14. Графики с двойной оцифровкой осей Может оказаться, что в одном графическом окне необходимо отобразить большее число графиков. Тогда следует прибегнуть к функции subplot, которая позволяет разделить область рисования на несколько прямоугольных областей равного размера, расположенных подобно элементам матрицы (пример 2.18): subplot (row, col, cur) ; Первые два аргумента задают количество рядов (row) и колонок (col). Третий параметр (cur) объявляет порядковый номер подобласти, в котором очередная функция plot будет строить свой график (рис. 2.15). f Пример 2.18. Деление области рисования » х=0:0.2:2*pi; » yl=sin(x}; » y2=cos(х); » y3=yl.*exp(-x); >> у4=у1.*у2; ~^ЩФ« ^
50 Глава 2 » subplot(2,2,1);plot(x#yl>; » subplot(2,2,2);plot(x,y2); » subplot(2,2,3);plot(x,y3); » subplot(2,2,4);plot(x,y4); - 1 :.*■?■■ "■ 0.5 0 •' -0.5 ■1c 0.4 0.3 0.2 0.1 0 *\ /\ ' \ , \ ) . 5 (\ \ 1 5 .-, 1- 1 0.5 0 -0.5 -1 D С ,:f 0 -0.5, 0 ( \ \ \ \ \ l\ \ ] / ■ / I J. ' 5' 1 Л / J V 5 1 3 . D 0 Рис. 2.15. Четыре подобласти в одном графическом окне 2.6.2. График функции в полярных координатах Полярными координатами <p,G) точки р (рис. 2.16) называются длина р радиус-вектора, проведенного из начала координат в точку р, и угол 6, образованный между осью х и этим вектором. Угол отсчитывается от положительного направления оси х к радиус-вектору против часовой стрелки. Довольно многие математические кривые с целью устранения неоднозначности принято задавать в полярной системе координат. Например, уравнение кардиоиды имеет вид: р = а- (1 + cps(p). Для построения графиков функций, заданных в полярной системе координат, вместо функции plot используется функция polar (пример 2.19).
Пошаговые вычисления в командном окне 51 У Рис. 2.16. Полярные координаты Пример 2.19. Построение графика в полярных координатах » phi=0:0.1:2*pi; » ro=5*(l+cos(phi)); » polar(phi,го) » t itle('Кардиоида') Результат построения кардиоиды для a=s приведен на рис. 2.17. Рис. 2.17. График кардиоиды в полярной системе координат
52 Глава 2 2.6.3. Использование логарифмического масштаба Единицы измерения значений ординат и абсцисс далеко не всегда соответствуют друг другу, и для создания более обозримого графика вдоль одной или обеих координатных осей приходится выбирать логарифмический масштаб. Для построения таких графиков используются функции loglo.g (логарифмический масштаб по обеим осям), semiiogx (логарифмический масштаб по оси х), semiiogy (логарифмический масштаб по оси у) — пример 2.20, рис. 2.17. ; Пример.2.20-Использование логарифмического масштаба -^^^^1¾¾¾¾ &у[ 1 » х=0:10:100; » у=ехр(х); » semiiogy(х, у) Рис. 2.18. График с логарифмическим масштабом по оси у 2.6.4. Построение графика функции на заданном интервале Довольно интересной модификацией функции plot является функция fplot, которая строит график функции y=f (х) без предварительного вычисления векторов (xl,x2, ...) и (у1,у2,...). Базовый формат вызова этой функции включает два аргумента: fplot (@nair,e_fun, [limits 1 )' fplot('name_fun', [limits])
Пошаговые вычисления в командном окне S3 В первом случае первым аргументом является указатель на функцию с именем name fun, во втором случае — строка с именем обрабатываемой функции. Аргумент limits может быть представлен либо двухкомпонентным вектором [xmin xmax], либо четырехкомпонентным вектором [xmin xmax ymin ymax]. Укороченный вариант задает пределы изменения аргумента х, расширенный — дополнительно представляет пределы изменения функции. Например: fplot(@sin, [D2*pi]) fplot('sin', [0 2*pi]) По сравнению с plot функция fpiot берет на себя вычисление таблицы значения функции, проявляя при этом некоторый интеллект — в местах резкого изменения функции значения аргумента х выбираются с более мелким шагом. Функция fpiot гарантирует, что относительное уклонение воспроизводимой функции отличается от ее идеального графика не более чем на 0,2%. Если вам нужен более точный или более грубый график, то после двух обязательных аргументов в функции fpiot можно задать желаемую относительную погрешность — число, меньшее I: fplot(Gsin, [0 2*pi], 0.05) В этом случае гарантировано построение графика, отличающегося от идеальной кривой не более чем на 5%. Еще один дополнительный параметр — целое натуральное число n требует, чтобы функция fpiot использовала при построении не менее чем n+i точку. Относительная погрешность и количество точек могут задаваться в любом порядке: fplot(@sin, [0 2*рд], 0.05, 20} fp!ot(@sin, [0. 2*pi], 20, 0.05) Наконец, как и в функции plot,, среди дополнительных параметров могут находиться строки, управляющие цветом и маркировкой графика. Последовательность задания всех дополнительных параметров — произвольная. Результат выполнения следующего оператора приведен на рис. 2.19: fpiot(@sin, [0 2*pi], 0.05, 's—'} Функция fpiot умеет возвращать значения компонентов векторов х и у, если к ней обратиться следующим образом: [х у] = fpiot(Gsin, [0 2*р1]); Функция f, указываемая в качестве первого аргумента fpiot, кроме независимой переменной х может содержать дополнительные параметры, например, y=f (x,al, а2). Тогда эти параметры указываются среди дополнительных аргументов после задания относительной погрешности и минимального числа точек: fplot('name_fun'f [xl х2], 0.05, 20, al, а2)
54 Глава 2 Рис. 2.19. Синусоида, построенная по fplot Довольно интересный пример, демонстрирующий ряд возможностей функции fpiot, приведен в справочных файлах. Советуем внимательно разобраться со всеми форматами вызова этой функции (пример 2.21), результат работы которых отображен на рис. 2.20. 50 °с 5 а 0 "'-Б Л \ ) \^\ ) 0.5 т.. 1 I *ч j ■ч. У I / /' \ / I -5; f 0 -.5 ж , 5 ■ 1 0.5 \ / I l/WvwvVV. ] 2 :. 4 - 6 J" ШШГ ■II1 о||| «:5 -1 Mill 1 Л 1/ V-; 0.02 0.04 -О.0Б 0.DS 0 1 Рис. 2.20. Примеры работы функции fplot
Пошаговые вычисления в командном окне 55 I Пример 2.21. Использование функции fplot » subplot (2,2,1), £plot[ehumps, Г 0 ] 1 ) » f = inline.('abs (exp[-j*x+ [0:9) )*ones(10,1)) ■) ,- » subplot(2,2,2), fplot(f,[0 2*pij) » subplot(2,2,3), fplot('[tan(x),sin(x),cos(x)]',2*pi*[-1 1 -1 1]) » subplot(2,2,4), fplot('sin(1 ./ x) ', [0.01 0.1],le-3) 2.6.5. Средства управления в графическом окне Из приводившихся выше примеров видно, что графики функций выдаются в специальном окне, снабженном меню и панелью инструментов. Это окно соответствует всем стандартам Windows — его можно перемещать по экрану, изменять размеры, сворачивать и разворачивать, удалять. По терминологии MATLAB оно представляет объект типа Figure и как пуповиной связано с пакетом MATLAB через встроенное меню. Так как термин фигура не очень удачно передает смысл и свойства этого объекта, мы будем пользоваться термином графическое окно. В принципе, каждое графическое окно в момент своего создания кроме автоматически формируемого заголовка (Figure I, Figure 2 и т. д.) может быть идентифицировано с помощью специального указателя (в английской терминологии — handle): hGWl = plot[х,у,...) Имя указателя выбирает пользователь. В дальнейшем, при работе с несколькими одновременно существующими графическими окнами указатель используется для выделения и редактирования компонентов соответствующего окна. Если нам нужно поработать с текущим графическим окном, то вместо своего указателя можно пользоваться соответствующим системным указателем. Его выдает функция gef (от англ. get handle to current figure — получить указатель текущего графического окна). Существуют и другие системные функции, возвращающие указатели, например, на оси графика дса (от англ. get handle to current axis — получить указатель текущего объекта типа axis (ось)), на текущий графический объект дсо (от англ. get handle to current object — получить указатель текущего объект) и др. Использование указателей подобного рола более подробно рассматривается в гл. 7. Меню, встроенное в графическое окно, позволяет: П обратиться к довольно мощному редактору свойств графических объектов; П сохранить графическое окно в файле с расширением fig; П перейти в среду MATLAB и выполнить любые действия в командном окне. :i Зак хад
56 Глава 2 На рис. 2.21 приведены развернутые меню наиболее важных пунктов главного меню графического окна. File | New Open... Close Save- Save As... Generate M-Flle... Import Data... Save Workspace As... Preferences... Export Setup..„ Page Setup... Print Setup... Print Preview... Print... Edlt| J-1-.lo ■ tCut Copy Clear Vlew| " Figure Toolbar Camera Toolbar Plot Edit Toolbar Figure Palette Plot Browser Property Editor SelectAII Ctrl+A Copy Figure Copy Options... Figure Properties... Axes Properties... Current Ot Colormap. Find Files. Clear Flgur sject Properties... , e Clear Command Window Clear Command History Clear Wert space Insert | X Label Y Label 71-Ы Title Legend Colorbar Line Arrow Text Arrow Double Arrow TextBox Rectangle Ellipse Axes Light Tools | V Edit Plot Zoom In ': ,- Zoom Out Pan Rotate 3D Data Cursor Reset View .., Options Pin to Axes " ' Snap To Layout Grid View Layout Grid Smart Align and Distribute Align Distribute Tool... Align Distribute > » » Basic Fitting Data Statistics Рис. 2.21. Основные команды меню графического окна Первая группа команд в меню File (Файл) позволяет закрыть графическое окно (Close (Закрыть)), вызвать в него ранее сохраненный графический файл (Open (Открыть)) или начать вручную создавать новый график, используя при этом возможности Property Editor (Редактор свойств) графического объекта (New Figure (Новый графический объект)). Команды второй группы позволяют сохранить графическое окно под прежним (Save (Сохранить)) или новым (Save As (Сохранить как)) именем, а таюке экспортировать его в нужном вам графическом формате (Export Setup (Параметры экспорта)). Список графических форматов, который доступен пользователю MATLAB, приведен в табл. 2.9. Таблица 2.9 № Наименование графического формата Расширение файла 1 Enhanced metafiles 2 Bitmap files 3 EPS (Enhanced PostScript) files emf bmp eps
Пошаговые вычисления в командном окне 57 Таблица 2.9 (окончание) № Наименование графического формата Расширение файла 4 EPS Color files 5 EPS Level 2 6 EPS Level 2 Color 7 Adobe Illustrator files 8 JPEG images 9 TIFF images 10 TIFF no compression images 11 Portable Network Graphics files 12 Paintbrush 24-bit files 13 Portable Bitmap files 14 Portable Graymap files 15 Portable Pixmap files eps eps eps ai ipg tif tif png pcx pbm pgm ppm Очень интересен результат выполнения команды Generate M-File (Генерировать М-файл) — в предыдущих версиях такой команды не было. Она позволяет автоматически создать функцию построения графиков, расположенных в графическом окне. Например, для графика Двух кривых, представленного на рис. 2.10, MATLAB автоматически генерирует следующий файл: function createfigurefxl, yl, у2) %:CREATEFIGURE (XI, Yl, Y2) % XI: vector of x data % Yl: vector of у data % Y2: vector of у data % Auto-generated by MATLAB on 03-Sep-2004 22:3.5:57 %% Create figure figurel = figure ('PaperPosition', [0.6345 6.345 20.3 15.23], • Pape.rS.ize ',[20.98 2 9.68]) ; %% Create axes axesl = axes(... 'YColor',[0 0 1],
58 Глава 2 ■YTick', [-1 -0.5 0 0.5 1.1, ... 'Parent', figure]); axis(axesl,[О 7 -1 1]); hold [-axesl,'all'); %% Create plot plonl = plot(xl,yl,'Parent',axesl); '%%■ Create axes axes2 = axes (... 'YColor', [C 0.5 0], . .. 'YAxisLocation','right',... 'YTick',[-2-10 1 2],... 'Parent', figured ); axis(axes2,[0 7 -2 2] ) ; l-i©ld(axes2, 'all') ; %% Create plot plot2 = plot(xl,y2,'Parent*,axes2); Если этой функции передать в качестве параметров векторы xl, yl и у2, то она воспроизведет указанный график. Заметим, что наше построение потребовало всего 3—4 команды. Изобилие строк в автоматически созданной программе объясняется тем, что в ней предусмотрено создание всех элементов фигуры — собственно графического окна, осей и их разметки, графика кривых. Может быть, к такого рода процедуре следует прибегать только в гом случае, когда пользователь провел вручную достаточно большую редакторскую правку. Команды import Data (Импортировать данные) и Save Workspace As (Сохранить рабочее пространство как) уже упоминались при описании главного меню. Команда Preferences (Предпочтения) выводит нас в окно установок параметров системы MATLAB, но целесообразность ее включения в меню графического окна вызывает сомнение. Аналогичная возможность входи г в состав меню File (Файл) командного окна. Команда Export Setup (Параметры экспорта) вызывает диалоговое окно, в котором можно просмотреть и изменить значения текущих параметров графического окна и графика — размеры (Size), способ визуализации (Rendering), характеристики шрифта (Font) и свойства линий (Lines). После этого откорректированный график можно сохранить в файле с расширением fig.
Пошаговые вычисления в командном окне 59 Оставшиеся команды последней группы меню File (Файл) связаны с подготовительными работами по настройке параметров графика, листа бумаги и принтера перед выдачей окончательной команды вывода (Print (Печать)). Команда Page Setup (Параметры страницы) вызывает диалоговое окно, снабженное четырьмя вкладками. Первая вкладка (рис. 2.22) позволяет вручную (Use manual size and position (Ручная установка размеров и полей страницы)) установить размеры полей (Тор (Сверху), Left (Слева), Width (Ширина) и Height (Высота)) поля графика в удобных для пользователя единицах измерения (Units (Единицы измерения)). В противовес ручной установке размеров и позиций имеется возможность разместить экранный образ в центре страницы (Use screen size, centered on page (Использовать размер экрана, разместить по центру)). Page Setup - Figure 1 Q Size and Position I Paper | Lines and Text I Axes and Figure | Mode ' -~?m r Use screen size, centered on page <• Use manual size and position [-Manual size and position Top: fe.-m I Use defaults Left Width: Height: 20.30 1 Fill page |l5.23 Щ' Unlts:| centimeters _£]' Fix aspect ratio Center Sample Г5Й1 Help.. OK Cancel Рис. 2.22. Установка размеров и позиций графика на странице Вкладка Paper (Бумага) позволяет выбрать формат листа бумаги (в наших условиях чаше всего А4) и установить его ориентацию (в высоту — Portrait (Книжная), в ширину — Landscape (Альбомная)). На вкладке Lines and Text (Линии и текст) можно отказаться от конвертирования цветов, если ваш принтер умеет печатать в цвете. Более интересные возможности предлагает вкладка Axes and Figure (Оси и рисунок) — рис. 2.23. Она позволяет изменить пределы и разметку осей но
60 Глава 2 отношению к образу на экране, изменить фон графика на белый цвет, включить печать элементов управления, установленных в области графического окна, произвести пересчет графического образа в зависимости от выбранного инструмента (ZBuffer, OpenGL и др.). Page Setup - Figure 1 Hi и .1« Size and Position | Paper | Lines and Text -. . ■ ? • * »i ■ ■ Web 111 i lllb dl IU LILtSt, <* Recompute limits and ticks ■ .■ <*" Keep screen limits and ticks путы tUIIUUIb i --„ -. I? Print UlControls, . ■: * 1 \ ,. Backgioiino tuiui '-<• Force white backflround * _■" f Keep screen.backflroynd color . ■ Figure rendaiKi .- ■ ■; |Default(auto mode) т| - . ■ ' - , ,r (_ ■ -¾. ,>u.:r- ■ -■ Axes arjd Figure | Ь sanpfe IokI '... ■ .,1 ,. L.j Help.. ,-ur Jw'i OK J '- Cancel • .v. ; ..".. .- " -: Рис. 2.23. Изменение параметров графика 2.6.6. Редактирование графиков Меню Edit Меню Edit (Правка) — см. рис. 2.21 — включает набор стандартных команд, присутствующих в любом текстовом или графическом редакторе — Undo (Отменить ввод), Cut (Вырезать), Сору (Копировать), Paste (Вставить), Clear (Очистить) и Select All (Выделить вес). Команда Edit | Figure Properties (Правка | Свойства графического объекта) вызывает Property Editor (Редактор свойств), который пристыковывается к графическому окну (рис. 2.24) и предварительно настроен на изменение свойств фигуры (Figure). В появившихся окнах редактора отображены наиболее употребительные параметры фигуры. Вы можете изменить заголовок графического объекта (Figure Name), сменить цветовую палитру (Colormap),
Пошаговые вычисления в командном окне 61 указать цвет окаймления поля графика (Figure Color), включить или отключить воспроизведение порядкового номера графического окна (Show Figure Number). С помощью кнопки Inspector (Инспектор) вызывается Property Inspector (Инспектор свойств), в котором отображаются все свойства фигуры. Любое из них, не включенное в наиболее употребительный набор, тоже может быть изменено. Более подробная информация о свойствах всех графических компонентов и технике работы с Property Inspector (Инспектор свойств) приводится в гл. 7 и 8. Из окна Property Editor (Редактор свойств) можно вызвать диалоговое окно Export Setup (Параметры экспорта). ■> Figure 1 File Edit View Insert Tools Desktop Window Help d &a a i|¥l Q ®t f? ®»vM d m \ о m 0.5 0 "'-0.5 ( , Prope j Figure Name Cdormap: 1 Figure Color 1 В 4 ' ' ■ ' У / ~s- \ 4 V / J ' 1 2 3 A 5 6 rty Editor - Figure л i 0 ж r.) P Show Fljjure Number Inspector... li | HI: '$Mjet jj Exponsaup... | Ф»-| i Рис. 2.24. Редактор свойств графического окна (Figure) Если в графическолг окне выделить оси, щелкнув по одной из них, то в окнах Property Editor (Редактор свойств) появляются свойства осей (рис. 2.25) и меняется' заголовок (Property Editor — Axes). Вы можете изменить заголовок, расположенный над полем графика (Title), установить цвета осей, подписей и фона поля графика (Colors), включить или отключить изображение координатной сетки по любой из осей (Grid), включить или отключить обводку рамки поля графика (Box). Для каждой из координатных осей можно
62 Глава 2 изменить наименование оси (X Label, Y Label, Z Label), минимальный и максимальный пределы изменения соответствующей переменной (X Limits, Y Limits, Z Limits), способ масштабирования по каждой из осей (X Scale, Y Scale, Z Scale), сменить направление оси на противоположное (Reverse). Кнопка Ticks (Штрихи) вызывает Edit Axes Ticks (Редактор штрихов), вид которого приведен на рис. 2.26. С его помощью можно выбрать один из трех вариантов размещения штрихов — автоматический (Auto), ручной (Manual) или с заданным шагом (Step by), задать автоматический или ручной способ индикации каждого штриха (X Tick Labels), включить или отключить режим отображения малых штрихов (Show minor ticks). Кнопка Inspector (Инспектор) в окне Property Editor (Редактор свойств) вызывает инспектор, отображающий значения всех свойств координатных осей. лА Figure 1 File Edit View Insert Tools Desktop Window H< D с? И в РГД ё*. О ® !'€, Q m □ □ э1р 05 -0 5 Г 4. / \ ' 0 12 3 4 5 Property Editor - Axes Title: X Axis | у Axis | Z Axis | Font | Colors: c Grl» Г Г XUfcel: I Ticks... — ' —— 1 X Llrrftsi |0 to |7 Г Auto x rv Гг , 1 ,_ X Seete: | Li.. j^J \ Reverse Box 6 11 1 .. 1 0 -I r X Inspector... 1; Рис. 2.25. Редактор свойств осей координат (Axes) Выделение той или иной кривой (рис. 2.27) приводит к перенастройке редактора свойств на параметры указанного графика (Property Editor — Line- series). Раскрывающиеся списки X/Y/Z Label Data Source (Источник данных) позволяют изменить значения векторов х, у и z, задающих табличную
Пошаговые вычисления в командном окне 63 функцию. После изменения любого из этих элеменюв необходимо нажать кнопку Refresh Data (Обновить данные), и тогда новые числовые значения вступят в силу. -JfcEdit Axes Ticks jXAxis]) Y AxisI ZAxlsl □ X Tick Locations: <*" Auto С Manual X Tick Labels: <*■ Auto С Manual Г Step by: J Locations: Labels: 0 0 _ .... _ 1._ Jl " . 2 _ 2 ._ ... "_ ..3..,. _3 - Л . 4 J_4 __.....! sj.i ~; ,_ _G !_6- ~7 П " Insert Delete I- Show minor ticks OK Apply Cancel Рис. 2.26. Редактор штрихов на координатных осях На рис. 2.28 показаны раскрывающиеся списки и подсказки к соответствующим окнам. В раскрывающемся списке Plot Туре (Тип графика) вы можете выбрать один из пяти способов отображения графика функции. По умолчанию график воспроизводится линией (Line, отсюда и фрагмент заголовка окна — Lineseries). Четыре других способа воспроизведены на рис. 2.29. В раскрывающемся списке Line (Линия) задается тип линии (сплошная, штриховая, пунктирная или штрих-пунктирная). Значение no line (нет) заменяет линию графика маркерами в заданных точках. Цвет линии и ее толщина регулируются значениями, установленными при помощи кнопок- списков, выделяемых подсказками Color (Цвет) и LineWidth (Толщина линии) соответственно. В списке Marker можно выбрать подходящую конфи-
64 Глава 2 гурацию маркера, размер которого задается значением в раскрывающемся списке MarkerSize. Цвета контура маркера и его внутренней области устанавливаются с помощью кнопок-списков MarkerEdgeColor и MarkerFace- Color соответственно. -> Figure 1 File Edit View insert Tools" Desktop Window Help D c? о а (¥|Д $.<"? ®' Щ i D El □ □ 1 0.9 0 ,0.5 Prope ; DJsplayNnrr ■ V Data Sou ; ZDetoSour ; ВПЕЗ .-4 \ / V \ .- / ■" \ ■Л .•' / ■V / .4.. .,-' , Э 1 2 3 A 5 6 rty Editor - Lineseries 1 0 f « | Plot Type- JLlne jj trispertur... |: се |м»с zi bne l~—Zl los Zi s£" | ~ <ж | J Marten |ic. _^J |бл _J &-( ^,- -1 zJ 1 1 1 .. i Рис. 2.27. Редактор свойств выделенного графика (Lineseries) Команды Edit | Axes Properties (Правка | Свойства осей) и Edit | Current Object Properties (Правка| Свойства объекта) вызывают Property Editor (Редактор свойств) с одновременной настройкой на параметры соответствующего объекта. Команда Edit | Find Files (Правка | Найти файлы) появилась только в MATLAB 7. Она позволяет устроить поиск заданного контекста во всех файлах текущего каталога. Аналогичным инструментом обладают практически все оболочки операционных систем и достаточно развитые системы программирования. Команды последней группы обеспечивают очистку поля фигуры, командного окна, окна истории команд и рабочего пространства. По умолчанию очистка трех последних компонентов сопровождается запросом подтверждения на выполнение операции.
Пошаговые вычисления в командном окне 65 г Color Property Editor - Lineseries Display Nome: j X Date Source: | auto V Dale Source: | d d r-Plot Type: Line Z Data Source: | d "3 (Trie "71 Ber Area Stelrs Stem —Line: | jj 10.5 jj: Msrtor; | no... jj 16.0 d Inspector.. Refresh Data &'\ £'\ MarkerEdgeColor L MarkerFaceColor LineWidth •-MarkerSize Рис. 2.28. Средства редактирования выделенного графика Ваг Area / \ \ в х ■ \ "V т Л i i.«? / j w/ Stairs Stem Рис. 2.29. Способы отображений табличных функций Кроме кнопок, обеспечивающих создание, открытие, сохранение и печать графического объекта, на панели инструментов находятся следующие кнопки (рис. 2.30): П Edit Plot — включение режима выделения графического объекта; □ Zoom In — увеличение масштаба изображения; □ Zoom Out — уменьшение масштаба изображения;
66 Глава 2 |- New Figure Г Open File - Save Figure Print Figure ■Pan Rotate 3D Data Cursor «^ I'icruire 1 'ile Б It View Insert ool esktop Window Help йене' fe i «*. s. « ®! «JO Ш\ ь_п I- Zoom Out Zoom In L Edit Plot L Show Plot Tools Hide Plot Tools L Insert Legend Insert Colorbar Рис. 2.30. Панель инструментов графического окна •> Figure 1 File Edit View Insert Tools Desktop VV 1 -1, 1 0.5 \ w- o\ -0.5 \ .-1 ~* "^ f 6 8 indow и П V Help ■—r ' 2 4 НПП ■л 0 Рис. 2.31. Вращение плоской кривой □ Pan — захват кривой с целью ее перемещения в поле фафмка; П Rotate 3D — вращение изображения (больший эффект достигается для 3D-noBcpxHOCTefi. пример вращения плоской синусоиды приведен на рис. 2.31);
Пошаговые вычисления в командном окне 67 П Data Cursor — включение режима, при котором точка графика, попавшая под курсор, сопровождается отображением значений координат (рис. 2.32); П Insert Colorbar — включение столбика с палитрой цветов (Colormap), отражающего распределение высот z; П Insert Legend — вставка автоматической легенды; П Show Plot Tools — пристыковка к графическому окну средств редактирования и просмотра (Figure Palette (Редактор графического окна), Property Editor (Редактор свойств), Plot Browser (Просмотр графика)); □ Hide Plot Tools — удаление средств редактирования и просмотра. •> Figure 1 File Edit View Insert Tools Desktop Window Help D.c*H_a-fe ®^f)©-RT| DE n □ ■ „■ 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 -0.8 ' ,~ V \ / \ / "■ ' X 7 i I Y DE75^ 7 / \ : \ \ / \ / \ i / \ / 0 12 3 4 5 6 ИПП ■ai — 7 Рис. 2.32. Идентификация точки на кривой Меню View Команды меню View (Вид) позволяют отобразить (команда помечена галочкой) на экране или скрыть следующие средства редактирования (см. рис. 2.21): П Figure Toolbar — панель инструментов графического окна; П Camera Toolbar — панель инструментов для управления камерой;
68 Глава 2 П Plot Editor Toolbar — панель инструментов для редактирования графика; П Figure Palette — редактор графического окна; □ Plot Browser — средство просмотра графических объектов; □ Property Editor — редактор свойств графических объектов. Перечисленные средства, исключая описанный выше Property Editor (Редактор свойств), приведены на рис. 2.33. •> Figure 1 File Edit View Insert Tools Desktop Window Help '.' 0& Qi \\k\ГСёП?1? ® i чёТП IS ro "rZT"' """"" .S К $:k .ft * *' "L.4. JL_4 L?.||в.1& ©Z Z * s л_ a_j_» / i^gi>-\\\4TD6|-al Figure P... * ИПП I Figure Toelbar| I Camera Toolbar I I Plot Edit Toolbar I Plot Browser x ■*■ New Subplots О I'D Axes. l^.. 3D Axes Шу 1x63 1x63 V Annotations \Line \Ajtuw X Doubifi A»:xw ^ Text Arrow T lexi Box j I Rectangle Osiqise 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 -0.8 ll -1 0 ' /\ 7 \ / \ \ \ \ ■ / ! / P/ Axes (no title) 17 Рис. 2.33. Графическое окно со средствами редактирования Камера (Camera), или точка зрения, определяет позицию человека, наблюдающего за.объектом, расположенным в поле графика, параметры источника света, способы распространепия и отражения лучей света. Более подробно свойства камеры описываются в гл. 10. Редактор графического окна (Figure Palette) и соответствующая панель инструментов (Plot Editor Toolbar) рассматриваются ниже. Окно Plot Browser (Просмотр графика) отображает список графических объектов, расположенных в поле графика.
Пошаговые вычисления в командном окне 69 Меню Insert Меню Insert (Вставка) — см. рис. 2.21 — содержит набор команд по вставке в графическое окно различных элементов оформления — легенды (Legend), разноцветной полоски (Colorbar), линии (Line), различных стрелок (Arrow, Double Arrow, Text Arrow), пояснительной подписи (Text Box), прямоугольников (Rectangle) и эллипсов (Ellipse). Вес эти команды дублируют возможности Figure Palette (Редактор графического окна) и Plot Edit Toolbar (Панель инструментов редактирования графика). Команда Insert | Light (Вставка | Свет) подключает к графическому окну Property Editor (Редактор свойств) источника света (Property Editor — Light), с помощью которого можно изменить позицию (Position — х, у, z), стиль (Style) распространения лучей света (бесконечно удаленный — Infinite, локальный — Local) и цвет лучей (Color). Меню Tools Значительно расширен по сравнению с предыдущими версиями набор команд меню Tools (Сервис) — см. рис. 2.21. Команды Edit Plot (Редактировать график), Zoom In (Увеличить масштаб), Zoom Out (Уменьшить масштаб), Pan (Захватить), Rotate 3D (ЗО-поворот) и Data Cursor (Данные под курсором) продублированы аналогичными кнопками на панели инструментов Figure Toolbar (Панель графического объекта). Команда Reset View (Восстановить вид) возвращает па исходное место график, перемешенный в режиме Pan (Захватить). Команда Options (Параметры) открывает список команд (рис. 2.34), с помощью которых можно изменить режим масштабирования, траекторию перемещения графика, захваченного в режиме Pan (Захватить), и способ отображения координат точки, выделенной курсором: П Unconstrained Zoom, Unconstrained Pan — естественное масштабирование (одновременно по всем координатам) или естественное перемещение графика (по траектории движения мыши); □ Horizontal Zoom. Horizontal Pan — масштабирование или перемещение по горизонтали; □ Vertical Zoom, Vertical Pan — масштабирование или перемещение по вертикали; П Display Cursor as Datatip — значения координат точки, находящейся под курсором, отображаются рядом с курсором; П Display Cursor in Window — координаты помеченной точки отображаются под полем графика. Для удаления неудачно оцифрованной точки можно прибегнуть к услугам всплывающего меню (рис. 2.35). Кроме удаления только что сделанной пометки (Delete Current Datatip), можно удалить все метки (Delete All Datatip),
70 Глава 2 изменить точку привязки цифровой отметки (Mouse Position — в позиции мыши или Snap to Nearest Data Vertex — в ближайшей табличной точке) и ее местоположение. 1 * Unconstrained Zoom Horizontal Zoom Vertical Zoom * Unconstrained Pan Horizontal Pan Vertical Pan 0.8 06 (14 0,2 n -0.2 -0 4 -0.6 -0.8 •'( - / . / 1 1 7 ) \ i \ 2 - \ \ \ \ \ V 3 2 Ш \ / ■ \ / \ / \ / / '■ / 4x. 3 2 V: -U UMTJ/ Рис. 2.34. Дополнительные возможности команды Options Selectton Style - Display Style Create New Datatip Delete Current Datstlp Delete All Datatlps '.av;t.- " --1 ■ ■-■- Mouse Position ■ ► Alt-Click Delete •* Snap to Nearest Data Vertex Window Inside Figure ' Datatip Рис. 2.35. Всплывающее меню Очень интересные возможности предлагает команда Pin to Axes (Прикрепить к осям), которой на панели инструментов соответствует кнопка, напоминающая современную кнопку, используемую для закрепления объявлений. Например, можно направить копчик стрелки с пояснительным текстом (Text Arrow) в особую точку графика и "кнопкой" закрепить его. Если теперь воспользоваться режимом Pan (Захватить) для захвата графика и его пере-
Пошаговые вычисления в командном окне 71 мещения, то кончик стрелки будет всегда следовать за прикрепленной точкой. Пояснительная надпись, расположенная на другом конце стрелки, при этом будет оставаться на месте. Если с помощью "кнопки" закрепить и начало стрелки, то перемещения кривой будут сопровождаться параллельными перемещениями стрелки и надписи. С возможностями выравнивания (Align) нескольких графических объектов по вертикали или горизонтали, выбора вертикальных или горизонтальных зазоров (Distribute) между объектами, привязки объектов к узлам координатной сетки (Grid) вы познакомитесь более подробно в разд. 8.3. Команда Tools | Data Statistics (Сервис | Статистика данных) позволяет получить стандартные статистические данные о кривой, представленной в поле графика. Результат исполнения этой команды для функции из примера 2.22 приведен на рис. 2.36. : "' ..»»..._. —Т • * ; I Пример 2.22. Аппроксимация графика •' » х=[0:0.8:6.28]; » y=sin(x); » plot (х,у) •JtData Statisti. SlaHsttcs (or | Creckto plot statistics on figure: 1 min I mean i metfHrT1 sW I гал^е J^ X 1 1 оГ SB Г 2еГ 1 96 Г S.6 v 1 t -D.53S? Г~ 0.9996 fl -0.0D62/? П •осгэй Г 0.И9Э .Г 1.ЭЭ6 1 Save to workspace- | Help | Qose | -> Figure 1 File Edit View Insert Tools Desktop Window Help BOB 1 0.8 0.6 0.4 0.2 Oii -0.2 -0.4 -0.6 -C.8 -1 datal Рис. 2.36. Статистика по графику синусоиды с редко заданными точками
72 Глава 2 Представим, что при построении графика мы неудачно распорядились шагом по аргументу и получили неудовлетворительную кусочно-линейную аппроксимацию исследуемой функции. Конечно, можно переделать соответствующую команду и получить хорошую синусоиду. Но график функции мог получиться в результате довольно сложных манипуляций, повторять которые не очень то и хочется. В этом случае можно поправить дело с помощью команды Tools | Basic Fitting (Сервис | Базовое сглаживание). В результате ее выполнения появляется диалоговое окно для выбора способа интерполяции таблично заданной функции. На рис. 2.37 выбрана интерполяция кубическим сплайном, а справа отображен результат применения этого метода. -yk Basic Select deta: [detal^J P Center and scale X deta ■Plot (lis- — ——— Check to display tits on figure 1? spErie interpoterfl Г shape-preserving HerpDlant P linear Г~ quadratic P cubic 1 4th degree polynomial P 5th-degree polynomial Г" 6th degree polynomial P 7th degree polynomial P 8th degree polynomial P 9th degree polynomial P 10th Oeeree polynomial P Show-equations- I P Signlficart digits: J 2 Plot residuals zl | Bar plot "3 ISubrjM P Show norm ol residuals Help- File Edit View Insert Tools Desktop Window.Help |П X 1 0.8 0.6(- 0.4 0.2 0<i -0.2 -0.4 -0.6 -0.8 -1 Л- f ■\ datal spline \ \ 7 ~=*4- Рис. 2.37. Интерполяция графика кубическими сплайнами Довольно много средств оформления графиков представлено в окне Figure Palette (Редактор графического окна) и продублировано соответствующими кнопками на панели инструментов Plot Edit Toolbar (Панель инструментов редактирования графика) — рис. 2.38. С помощью кнопок, обеспечивающих быстрый запуск действий, можно установить цвет фона на поле графика (Color Face), цвет выделенной линии (Color Edge), цвет пояснительных подписей (Color Text).
Пошаговые вычисления в командном окне 73 Font Г Bold г Insert Line Insert Arrow Insert Double Arrow Italic Г Insert Text Arrow -> Figure 1 .'File Edit ШП-ert Tools D=^SMQndoW He,P ^^-®1.«!jl ЕВ i QJ3 u Color Text L Color Edge L Color Face Pin to axes L Align Right L Align Center L Align Left Insert Textbox Insert Rectangle Insert Ellips Рис. 2.38. Панель инструментов Plot Edit Toolbar Align/Distribute Шесть следующих кнопок очень напоминают средства управления характеристиками текста, используемые в редакторе MS Word. Однако диалоговые окна здесь несколько иные. Например, диалоговое окно выбора шрифта и его характеристик представлено на рис. 2.39. Кнопки по изменению характеристик выделенного текста (Bold — жирный, Italic — курсив) и выравниванию строки в прямоугольнике Textbox (Align Left, Align Right и Align Center) имеют значки в стиле MS Word. Очередная группа из семи кнопок дублирует соответствующие строки Figure Palette (Редактор графического окна) и позволяет вставить на любое место графического окна отрезок прямой (Insert Line), стрелку (Insert Arrow), двунаправленную стрелку (Insert Double Arrow), стрелку с пояснительным текстом (Insert Text Arrow), текст в прямоугольнике (Insert Textbox), прямоугольник (Insert Rectangle), эллипс (Insert Ellipse). Для вставки нужного элемента следует выбрать соответствующую команду в Figure Palette (Редактор графического окна) или нажать аналогичную кнопку на панели инструментов, переместить курсор мыши в начальную точку графического окна и, удерживая левую кнопку мыши, протянуть элемент до конечной точки (примерно такая же технология используется в графическом редакторе Paint). На рис. 2.40 продемонстрирован результат работы Figure Palette (Редактор графического окна).
74 Глава 2 Шрифт Шрифт: Начертание: 30 '>Г ©PMingLiU '•t OSimSun *Г Academy Engraved LET" '*Г Amaze обычный курсив жирный жирный курсив -Оброзец" Hafiop символов: ВЕЗ Размер: |Кириллический 8 9 10 11 12 11 16 ▲ z\ OK Отмена ^3 Рис. 2.39. Выбор характеристик шрифта -> Figure 1 File Edit View Insert Tools Desktop Window Help Fi« re P ... x "^ New Sublets ГЗ Create tiled subplots -ffl ffl v-VenStiles. Ну ^ Annotations N^LITIC ^ Arrow ^ Doutfc Mrow ^ Text Arrow T TexlBox [ JRcclaruft: О Ellipse 1*63 1x63 Cancel ^J 0.5 / \ / НПЕЗ 0 5n Oi- НбПо, МАТ1.АБ П 12 05 / 0.5 Рис. 2.40. Результат работы редактора Figure Palette
Пошаговые вычисления в командном окне 75 Для создания четырех полей графика в графическом окне необходимо щелкнуть по кнопке с пояснительной подписью "Create tiled subplots" и в появившемся поле выделить нужное количество клеток по горизонтали и вертикали (очень напоминает технику формирования таблиц в MS Word). В каждом из появившихся окон вставлены описанные выше графические примитивы. Подключение русских текстов доставит головную боль отечественным пользователям MATLAB 7. В примере с воспроизведением кардиоиды (рис. 2.17) мы слукавили. Обычно результат работы команды title ('кардиоида') выглядит так, как показано на рис. 2.41. «> Figure 1 File Edit View Insert Tools Desktop Window Help КйОаеТёаг* & 10 „60 НПО 270 Property Editor - Text ^ I Interpreter: |тех Alignment; !P| ? Line Style: UrejV*fth. Г ~Б 0.5 Edfie COOK с^з | Background, ffi^l ~3 Fort: | Helvetica j[] ] 10.0 ][] Рис. 2.41. Так MATLAB 7 отображает русские надписи Объяснение тому достаточно простое. В шрифте Helvetica не совпадает кодировка русских букв. Для восстановления справедливости выделяем надпись и выполняем команду View | Property Editor (Вид | Редактор свойств). К графическому окну пристыкуется редактор свойств текста, в котором следует изменить шрифт. К сожалению, не все шрифты, которые доступны в
76 Глава 2 MS Windows (например, Times New Roman), видны из Property Editor (Редактор свойств). Поэтому приходится остановить свой выбор на шрифте Courier с установкой подходящей высоты символов (рис. 2.42). Также можно воспользоваться такими шрифтами, как Arial Cyr, MS Sans Serif, Small Font. -> Figure 1 File Edit View Insert_ Tools r^_sktop_^lndow Help ■Kapquouqap ■ A, ■ SO 10 12Cb-- Г-£-~д30 man Property Editor - Text 1 Line Style: p H Interpreter. | Tex^] Inspector- 1 LiraWldth: [ai ~^\ Wijnmenf. Bjgg Edae Colon |Д-| Fort: | Courier j Background &,-\ 3 hi.o zi Д' I Normal 3 | Normal ^ Рис. 2.42. Замена шрифта для русификации подписи 2.6.7. Включение графиков в отчетную документацию После того как вы построили и отредактировали график, отражающий тот или иной процесс, его можно включить в состав отчетного документа, например, набираемого в редакторе MS Word. Делается это. следующим образом: 1. В момент, когда графическое окно находится на экране, нажимается комбинация клавиш <Alt>+<Print Screen>, копирующая содержимое экрана в буфер обмена (clipboard).
Пошаговые вычисления в командном окне 77 2. В редакторе, в котором готовится отчет, необходимо выполнить команду Edit | Paste (Правка | Вставить). Средства MS Word позволяют после этого выполнить обрезку изображения, поворот, корректировку яркости и контраста и др. Более простой вариант копирования области графика в буфер обмена выполняет команда Edit | Copy Figure (Правка | Копировать рисунок). В этом случае вам не понадобится удалять лишние фоновые фрагменты, т. к. в буфер обмена попадет только поле графика без заголовка графического окна. 2.7. Деловая графика Довольно много различных приложений, связанных с экономическими, статистическими и социологическими исследованиями, используют для визуализации результатов различного рода диаграммы — столбиковые и круговые, плоские и объемные. Иногда их связывают с термином "деловая графика". В библиотеке графических функций MATLAB для этой цели реализована Группа следующих функций: bar, barh, ЬагЗ, ЪагЗп, pie, pie3, area. 2.7.1. Плоские столбиковые диаграммы В простейшем случае плоская столбиковая диаграмма, отражающая значения компонентов вектора у, строится с помощью функции bar (пример 2.23). ! Пример 2.23. СтоЛби^вая диаграмгиа ■. f"" : » у=[1 2 41; » length(у) :ans = 3 » bar(у); colormap(cool) Функция colormap, к которой мы обратились с аргументом cool, осуществляет подмену стандартной цветовой палитры, закрепленной за графическим окном. Палитра, по умолчанию приписываемая графическому окну, отличается довольно мрачными тонами. Новая палитра представляет набор более светлых оттенков от бирюзового (cyan) до малинового цвета (magenta). На рис. 2.43 показана построенная диаграмма. По умолчанию ее столбики расположены над целочисленными координатами х, принадлежащими интервалу [l, length (у)]. Ширина столбиков по умолчанию равна 0,8 см (этот размер точно выдерживается только при выводе на принтер). Надписи внутри столбиков сделаны вручную с помощью средств управления фафическим т
78 Глава 2 окном. Вид диаграммы не изменится, если вектор у будет представлен столбцом с такими же значениями (у= [1,-2,-4]). 4 3.5 Э 2.5: 2 1.5 1 0.5 0 • у = 1 у = 2 у = 4 - 1 2 3 Рис. 2.43. Диаграмма значений вектора у=[1, 2, 4 ] Обращение к функции barh с тем же аргументом строит столбики, развернутые по горизонтали (рис. 2.44): » barh{y); colormap(cool) 3 2 1 0 0.5 1 1.5 2 25 3 35 Л Рис. 2.44. Горизонтальная диаграмма J 1 1 L. Обращение к функциям bar (пример 2.24) или barh с двумя аргументами (х, у) позволяет изменить маркировку оси л- (рис. 2.45). Правда при этом требу-
Пошаговые вычисления в командном окне 79 ется, чтобы вектор х был представлен монотонно изменяющимися значениями (возрастающими или убывающими). [Пример 2.24. Маркировка оси у диаграммы . » х=[-1-5,0,2.5]; » у=[1,2,4]; ». bar{к,у); » colormap(cool) 3.5 3 2.Б 2 1.S 1 0.5 0, - ■ - - Э-2-1-0 1 2 3 i Рис. 2.45. Диаграмма с заданной разметкой оси х Аргумент w в обращениях bar(y,w) или bar(x,y,w) управляет шириной столбцов диаграммы. В зависимости от маркировки оси х и заданной ширины столбиков v/ соседние прямоугольники могут накладываться друг на друга. Аргумент у может быть представлен не только вектором, но и матрицей значений (пример 2.25). ': Пример 2.25. Построение нескольких диаграмм одновременно » у=[1 2 4; 1.5 3 5] У =* 1.0000 2.0000 4.0000 1.5000 3.0000 5.0000
80 Глава 2 В этом случае функции bar и barh предлагают два способа группировки столбиков, представляющих компоненты матрицы: » bar{у,"grouped*); colormap(cool) или » bar{y); colormap(cool) Любая из приведенных выше строк генерирует две группы столбиков (рис. 2.46). 4 3 " 2 1 0 -V.4 - у=1 т " Wit у=1.5 . ы т : :-т *& - ■ 1 2 „ Рис. 2.46. Матричная диаграмма, вариант 1 10 " 9 Л 8 ■к / 6 5 4 3 2 |у#^ а? а гЛ По тш У = 1 г ?&° 1¾ ■*;>?.. v '. If "л t 1 " !$..i ■ ;«к<. #4 ■"■■■■■■■-,-- 1 ^%ri-; = 1.5 Рис. 2.47. Матричная диаграмма, вариант 2
Пошаговые вычисления в командном окне 81 Второй способ группировки элементов этой же матрицы позволяет разместить столбики друг над другом (рис. 2.47): » bar(у,'stacked'); colorrnap(cool) 2.7.2. Объемные столбиковые диаграммы Объемные столбиковые диаграммы строятся с помощью функций ЬагЗ и bar3h, разница между которыми заключается только в вертикальном или горизонтальном расположении столбцов. Функция bar3{z) превращает простую плоскую диаграмму в объемную (рис. 2.48): » z=[l,2,3]; » bar3{z); colorrnap(cool) Рис. 2.48. Простая объемная диаграмма Если аргумент z представлен матрицей, то столбики размещаются как вдоль оси у, так и вдоль оси х (рис. 2.49): » z=[2,3,4;l,2,3]; » ЬагЗ{z); colorrnap(cool) Столбики двумерной матрицы могут быть перегруппированы двумя разными способами с использованием аргументов grouped (рис. .2.50) и stacked (рис. 2.51): » z=[2,3,4;1,2,3]; » ЬагЗ (z,'grouped') ; colorrnap (cool) » ЬагЗ(z,'stacked'); colorrnap{cool)
82 Глава 2 Рис. 2.49. Матричная объемная диаграмма Рис. 2.50. Способ группировки grouped В приведенных выше примерах разметка осей у и х выполнялась автоматически. Однако функции ЬагЗ и ЬагЗЬ допускают задание монотонно возрастающего или убывающего вектора у, с помощью которого может быть изменена разметка диафаммы вдоль оси у — ЬагЗ (у, z). С помощью еще одного параметра w можно управлять шириной столбцов — bar3(z,w) или ЬагЗ {у, z,w>. По умолчанию ширина столбиков равна.0,8 см.
Пошаговые вычисления в командном окне 83 Рис. 2.51. Способ группировки stacked 2.7.3. Круговые диаграммы Круговые диаграммы, состоящие из плоских или объемных секторов (аналогов кусков пирога), строятся с помощью функций pie и pie3 (пример 2.26). В простейшем случае вектор q, содержащий к положительных компонентов, генерирует к секторов, центральный угол которых пропорционален вкладу каждого компонента в общую сумму. По умолчанию против каждого сектора помещается его процентный вклад. ! Пример 2.26. Круговая диаграмма » q = [1,2,4]; >> colormap cool » pie(q) » pie3(q) Построение секторов в плоской диаграмме начинается с "севера" и осуществляется против часовой стрелки. Для объемных диаграмм начало отсчета располагается на "северо-западе". Результаты работы указанных команд приведены на рис. 2.52 и 2.53. На рис. 2.53 видно, что некоторые надписи расположены не Очень удачно. Для того чтобы обратить внимание на отдельный сектор или группу секторов, их принято немного выдвигать из "пирога".
84 Глава 2 '" 57% l Рис. 2.52. Плоская круговая диаграмма Рис. 2.53. Объемная круговая диаграмма Создание таких вьшеляюшихся элементов обеспечивается заданием еще одного аргумента такой же размерности, что и вектор q. Выдвигаемым секторам в новом векторе должны соответствовать ненулевые элементы. Например: » v=[0,l,0] ; » pie(g,v); % результат на рис. 2.54 » т=[1,0,0]; » pie3[q,m) % результат на рис. 2.55 Вместо процентных меток мы можем разместить свои надписи, предварительно сформированные в массиве ячеек (пример 2.27). 29% 14% 4 -;w&jI•k-Vi'- '■ "
Пошаговые вычисления в командном окне 85 Рис. 2.54. Выделен второй сектор Рис. 2.55. Выделен первый сектор !;Приме^.27; Метки на круговой диаграмме - д---;. . ■ *=. ■ ^. у- gg \ » z= [1.249-,1, 249,1,249,1,249] ; » s=('CeBep', ",'Запад ', ",'Юг',",' Восток',"); » pie(z,s); colormap(cool) В приведенном выше фрагменте кроется небольшой секрет. Во-первых, чтобы надписи сторон света были точно расположены на своих местах, пришлось завести для них очень узкие секторы и довести общее количество секторов до 8. Во-вторых, чтобы надписи Запад и восток не сливались с изображением, к ним пришлось добавить по паре пробелов. Результат приведен на рис. 2.56.
86 Глава 2 Запад ^ й-.; -:■ " Ь_ ч Север !' < I, '■- -- - V Иг Воолок Рис. 2.56. Стороны света на круговой диаграмме 2.7.4. Площадные диаграммы В площадных диаграммах график первой функции у: (х) строится обычным образом, отмеряя ординаты yi{xi) от оси х. График второй функции y.v(x) как бы наслаивается на предыдущий график, отмеряя свои ординаты от ординат предыдущей функции — yitxil+yHxi). График следующей функции суммируется с ранее накопленной суммой и т. д. Площадь каждого трафика выделяется своим цветом, чтобы продемонстрировать вклад очередного слагаемого в общую сумму. Пусть, например, итоговый график задан значениями элементов двумерного массива (пример 2.28). 1 Пример 2.28. Задание площадных диаграмм с помощью массива ' v = 18 3 7 5 '9 4 2 6 Его столбцы определяют значения функций-слагаемых. Это означает, что график первой функции задан точками (1, 1), (I, 7) и (1, 4), график второй функции — точками (1, S), (2, 5) и (3, 2), график третьей функции — точками (1, 3), (2, 9) и (3, 6). Каждый из компонентов в отдельности представлен графиками в отдельных подокнах (рис. 2.57). Соответствующая площадная диаграмма воспроизведена в правом нижнем подокне с помощью функции а-геа: » у=[1 8 3; 7 5 9 ; 4 2 6]; » yl=[l,7,4];
Пошаговые вычисления в командном окне 87 » у2=[8,5,2]; » уЗ=[3,9,б]; » subplot[2,2,1); plot(у1);grid on » subplot (2,2, 2).; plot (y2) ;grid on » subplot(2,2,3); plot(y3);grid on » subplot(2,2,4); area(y); grid on; colormap(cool) Рис. 2.57. П/ющадная диаграмма и ее составляющие <1 3<ш S99
Глава 3 Типы данных 3.1. Иерархия типов данных в MATLAB В справочных файлах приведена схема (рис. 3.1), на которой представлены I6 фундаментальных типов данных (или классов), определенных в MATLAB. Из схемы явствует, что базовым классом данных является массив (array). Наряду с пустыми, неинициализированными массивами язык MATLAB позволяет обрабатывать векторы (массивы размерности lx/j или ях1), квадратные и прямоугольные матрицы (массивы размерности пхт), массивы более высокой размерности. ARRAY char cell NUMERIC int8. uint8, int16, uint16, int32, uint32. int64, uint64 single stucture I user class Java class LOGICAL function handle double I sparse Рис. 3.1. Схема иерархии типов данных В гл. 2 довольно подробно обсуждалась специфика представления числовых массивов с элементами типа double, положенных в основу большинства вычислительных процессов и сочетающих в себе представление как вещест-
90 Глава 3 венных, так и комплексных чисел. В этой главе мы остановимся более подробно на других классах данных. 3.1.1. Символьные массивы (char arrays) Символьные векторы (массивы размерности lx/z) представляют собой обычные строки. Для задания их значений в правой части оператора присваивания записывают цепочку символов, заключенную в одинарные кавычки (пример 3.1). ; Пример 3.1. Символьный вектор .-..-■>&*■ .£&-\ » sv='abedefgh' sv = abedefgh » whos Name Size Bytes Class sv 1x8 16 char array Grand tonal Is 8 elements using 16 bytes Мы уже упоминали, что каждый элемент типа char занимает в памяти 2 байта и представлен в кодировке ASCII Unicode. В MATLAB 7 устранены моменты, имевшие место в ранних версиях и связанные с неприятием русских букв "с" и "я": >> гд='пуля' rs = пуля » rs='условие' rs = условие Символьная матрица (массив размера /их/») должна состоять из строк равной длимы (пример 3.2). ; Пример 3.2. Символьная матрица » sm=l'abedefgh';Ч234567В'] sm = abedefgh 12345678 »■ whos
Типы данных 91 Name Size Bytes Class sm 2x8 32 char array Grand total is 16 elements using 32 bytes Дня определения текущих длин, размеров и количества измерений символьных массивов можно использовать функции length, size и ndims (пример 3.3). ! Пример 3.3. Определение размеров символьных массивов ,<л. } » sv='abedefgh'; » whos Name Size Bytes Class sv 1x8 16 char array Grand total is 8 elements using 16 bytes » size(sv) % возвращает число строк и число столбцов ans = 1 '8 » length(sv) % возвращает количество символов ans = 8 » ndIns (sv) % возвращает количество измерений ans = .2 » sm=['abedefgh';'12345678'] sm = abedeigh 12345678 » size(sm) % возвращает число строк й. число столбцов ans = .2 8 » length(sm) % возвращает количество символов в строке (!) ans = 8" » ndims(sm) % возвращает количество измерений ans = 2
92 Глава 3 3.1.2. Целочисленные данные в MATLAB Ни один из универсальных алгоритмических языков не обходится без целочисленных данных. MATLAB до версии 7 в этом смысле стоял несколько особняком. Он допускал создание и хранение числовой информации в виде одно-, двух- и четырехбайтовых форматов со знаком или без знака. Во всех версиях пакета были предусмотрены функции конвертирования вещественных и комплексных данных типа double в любой из допустимых форматов целых и вещественных чисел (табл. 3.1), а также обратные преобразования. Однако арифметические операции над целочисленными данными до 7-й версии были запрещены. Таблица 3.1 Функция Назначение Диапазон допустимых значений int8 Преобразование в формат однобайтовых целых чисел со знаком uirvte Преобразование в формат однобайтовых целых чисел без знака intl 6 Преобразование в формат двухбайтовых целых чисел со знаком uintl 6 Преобразование в формат двухбайтовых целых чисел без знака int32 Преобразование в формат четырехбайтовых целых чисел со знаком uint32 Преобразование в формат четырехбайтовых целых чисел без знака int64 Преобразование в формат восьмибайтовых целых чисел со знаком uint64 Преобразование в формат восьмибайтовых целых чисел без знака double Преобразование числового аргумента в формат вещественного числа с удвоенной точностью single Преобразование числового аргумента в формат вещественного числа с одинарной точностью от-128 до 127 от 0 до 255 от-32 768 до 32 767 от 0 до 65 535 от-2 147 483 648 до 2 147 483 647 от 0 до 4 294 967 295 от-263 до263-1 от 0 до 264 - 1 От 2.225x1 ГГЗСВ до 1.798x10+30В (по модулю) От 1.175x10"38 до 3.403x10+38 (по модулю) Версия MATLAB 7 принципиально отличается от предшествующих версий не только тем, что в нее включены восьмибайтовые целые числа. Самое существенное, что в новых целочисленных классах (кроме int64 и uint64)
Типы данных 93 определены все арифметические операции. Это может послужить важным аргументом при выборе типа данных для решения целочисленных задач с большими массивами информации. Например, в задачах обработки графических изображений цветовые атрибуты пикселов кодируются однобайтовыми значениями, которым соответствует тип uintB. Некоторые варианты обработки целочисленных массивов приведены в примере 3.4. I" "■-■■"" '- г ■"■ V- ;_£? :•"•■" : ! Пример 3.4. Целочисленные массивы -.*•-■ - > ; » x=intl6(l'2) х = 12 » whos Name Size Bytes Class x lxl 2 intl6 array Grand to"cal is 1 elements using 2 bytes » format hex » x X = 000c » y=uintl6([5 25 30]) У = 0005 0019 OOle » whos Name Size Bytes Class x lxl 2 intl6 array у 1x3 6 uintl6 array Grand total is 4 elements using 8 bytes Как вы заметили, вывод целочисленных данных неплохо уживается с форматом hex. Аргумент, преобразуемый к целому типу, может иметь дробную часть, и тогда MATLAB использует стандартное округление, принятое в математике (пример 3.5). ; Пример 3.5. Округление аргументов •' S" '-■. .* » int8(2.1) ans = 2 » int8 (2.5)
94 Глава 3 ans = 3 » int8(-2.5) ans = -3 » int(2.9) ans = 3 Максимальное и минимальное значения, соответствующие тому или иному целому типу, можно определить с помощью функций intmin и intmax: » intmin('intlб') ans = -32768 » intmax('uint8') ans = 255 Если конвертируемый аргумент выходит за пределы заданного диапазона, то MATLAB возвращает левую или правую границу: » int8(450) ans = 127 » int8(-450) ans = -128 Точно такое же обрезание происходит и при получении результата, выходящего за допустимые пределы: » intS(100)+int8[150) ans = 127 Вы можете включить режим выдачи предупреждения о выходе результата операции за допустимые пределы, обратившись к функции intv/arning с аргументом 'on': ». intwarning('on') » x=int8(200) Warning: Out of range value converted to intmin('int8') or intmax('int8').
Типы данных ■ 95 127 По умолчанию этот режим отключен (intwarningt 'off )). Функции формирования стандартных матриц ones, zeros и eye могут быть использованы для формирования целочисленных массивов при условии, что последним аргументом задается строка с указанием типа (пример 3.6). ^„,.г..^,...^™у^..^...,„у...........?. „ ;...„ ?!,.Г.,..^„„,^....„^^™^... „.„ .,....„. ! Пример 3,6. Формирование стандартных матриц ^Щ^лТ^щ? » x=ones{2,2,'int8') х = 1 1 1 1 » y=zeros(2,3,'uint8') У = 0 0 » г=еуе z = 1 .0 » whos Name X У z 0 0 0 0 (2,'intl6'> 0 1 Size Bytes 2x2 4 2x3 6 2x2 8 Class lnt8 array uint8 array intl6 array Grand total is 14 elements using 18 bytes Целочисленная арифметика в MATLAB 7 налагает ряд ограничений на допустимые сочетания операндов, участвующих в выражениях. Так, например, целочисленные операнды, входящие в формулу, должны быть одного типа. То есть нельзя складывать однобайтовый скаляр или массив с двухбайтовым операндом. Однако если один операнд (скаляр или массив) имеет целый тип, то вторым операндом формулы может быть скаляр типа double (пример 3.7). MATLAB выполняет такую операцию с удвоенной точностью и преобразует результат к типу целочисленного операнда. Но когда количество операндов в формуле больше двух, то вычисления могут привести к неверным результатам (пример 3.8).
96 Глава 3 \ Пример 3.7. Комбинация целочисленного массива со скаляром типа double . » int8([I 2 34 5])*0.8 ans = 12 2 3 1 Следует отметить, что версия MATLAB 7, как и любой новый программный продукт, еще не прошедший достаточную обкатку, содержит определенное количество ошибок. Одну из них нам удалось обнаружить на примере 3.8. j Пример 3.8. Ошибка MATLAB. >> int8(10)/int8[100)*20.5 ans = О »■ 20.5*int8(10)/int8(100) ам = 1 С точки зрения программиста, обрабатывающего формулу слева направо, приведенные выше результаты можно объяснить, но не оправдать. После деления двух целых чисел (10/100) получается целочисленный 0, что и предопределило первый результат. Во второй формуле MATLAB "сообразил", что результат первого умножения (205) надо преобразовать к типу ints (т. е. заменить на 127) и после деления на 100 получил целочисленную 1. С точки зрения математика здесь нарушен закон коммутативности (перестановка сомножителей привела к разным результатам). Видимо, правильней было бы выполнить все операции в формате double, получив 2.05, а затем преобразовать результат в целочисленный, т. е. в 2. Еще одну несуразицу с перестановкой слагаемых удалось обнаружить на примере 3.9. j Пример 3.9. Другая ошибка MATLAB '" • » 0.5+int8(10)/int8[120) ans = 1 » CL25+int8(10)/inc8(100)+0.25 ans = 0
Типы данных 97 С точки зрения математика обе формулы идентичны, а результаты вычислений это не подгверждают. Над целочисленными операндами без знака можно выполнять поразрядные битовые операции. Перечень соответствующих функций приведен в табл. 3.2. Таблица 3.2 Функция bitand(ft,B) bitor(А,В) bitxor(A,B) bitcmp(А,п) bitset(А,п) bitset(A,n,v) bitget(A,n) bitshift(A,n) Выполняемое действие Поразрядное логическое умножение Поразрядное логическое сложение Поразрядное исключающее ИЛИ Инвертирование а с сохранением п битов Установка n-го бита числа А в единицу Установка n-го бита числа А в значение v (0 или 1) Опрос значения n-го бита в числе А Сдвиг двоичного кода А на п разрядов влево (п > 0) или вправо (п < 0) В двоичных операциях действуют следующие правила. Оба операнда, участвующие в логических операциях and, or и хог, должны быть одного типа. Результат выполнения операций стр и set не должен выходить за разрядную сетку первого операнда. Те разряды, которые при операции сдвига выходят за пределы разрядной сетки, теряются. Ниже приведены результаты выполнения битовых операций над самыми короткими числами, которые легко проверить. » A=uint8([0 1; 0 1] ) ; » B=uint8[[0 0; 1 1] ) ; » T_AND=bitand(A,B) T_AND = 0 0 0 1 » T_OR=bitor(A,B) T_OR = 0 1 1 1 » Т XOR=bitxor{A,B)
98 Глава 3 T_XOR = 0 1 1 О » C=uint8(5); » bitcmpfc, &) ans = 58 » bitset(C,2) ans = 7 >> bitset [C, 3,0) ans = 1 » bitget(C,3) ans = 1 » bitget(C,2) ans = 0 >> bitshifUC,2) ans = 20 » bitshift(C,-l) ans = .2 3.1.3. Вещественные данные с одинарной точностью (single arrays) В отличие от данных типа double, где каждый элемент массива представлен одним или двумя 8-байтовыми значениями, в массивах типа single (single arrays) на каждую числовую составляющую отводится по 4 байга и тем самым экономится 50% памяти. Однако диапазон представления числовых данных здесь существенно ниже (I038 вместо 10308), да и точность вычислений гарантирует получение, максимум, 7—8 значащих цифр вместо 15—16 в стандартном режиме. В отличие от предыдущих версий MATLAB 7 разрешает почти все арифметические операции и над вещественными данными с одинарной точностью. Воспринимают такие аргументы и многие элементарные функции.
Типы данных 99 Более того, многие процедуры линейной алгебры в новой версии адаптированы таким образом, что могут решать соответствующие задачи с такими данными. При этом пользователь ничего не должен изменять в списке параметров той или иной процедуры (пример 3.10). | Пример 3.10 Массивы с одинарной точностью » x=single(5) х = 5 » whos Name Size Bytes Class x lxl 4 single array Grand total is 1 elements using 4 bytes » abs (y) ans = 1.1180 Следует заметить, что преобразование в формат single может привести к небольшим искажениям исходных данных. Это объясняется тем, что в двоичном коде числа может быть достаточно много дробных разрядов, которые при обрезании мантиссы и принятом правиле округления вызывают небольшую погрешность: >>forraat long » single(3.4) ans = 3.4000001 Ошибка на одну единицу в 8-й значащей цифре вполне допустима. Арифметика с одинарной точностью тоже накладывает определенные ограничения на операнды формулы, которые могут быть либо типа single, либо комбинироваться со скалярами или массивами типа double. Результат операции в последнем случае тоже имеет тип single: » x=single(5)+single{3) x = 8 >> y=single(5)+3 У = 8 >>■ whqs
100 Глава 3 Name Size Bytes Class x lxl 4 single array у lxl 4 single array Grand total is 2 elements using 8 bytes Для того чтобы узнать наименьшее и наибольшее значения для данных типа single, МОЖНО обратиться к функциям realmin и realmax с аргуменгом- строкой, задающей тип: » realmin('single') ans = 1.1754944е-038 >> realmax('single') ans = 3.4028235e+038 Если при вычислениях с данными типа single результат превосходит максимально допустимое значение этого типа, то MATLAB возвращает inf: » realmax('single')*2 ans = Inf 3.1.4. Разреженные матрицы (sparse arrays) Довольно много задач математической физики, теории прочности и пластичности приводят к решению специфических систем линейных алгебраических уравнений с так называемыми ленточными или блочными матрицами . Кроме нескольких диагоналей или небольших блоков, заполненных коэффициентами, в этих матрицах находится огромное число нулей (sparse arrays). Держать их в оперативной памяти невыгодно, поэтому в ряде прикладных программ было предложено хранить наряду со значениями ненулевых элементов их индексы. Способы такого представления данных могут быть разными. Например, можно хранить тройки (value, i, j). MATLAB использует более экономный вариант, при котором разреженная матрица рассматривается как вектор-столбеи, компонентами которого являются разреженные векторы-строки. Ненулевые компоненты разреженных строк требуют задания не двух индексов, а одного, на чем, собственно, и экономится объем хранимой информации. На самом деле хранятся не индексы отдельных элементов столбца, а диапазон индексов, соответствующий подряд идущим ненулевым элементам. В MATLAB предлагается довольно много функций по обработке разреженных матриц и по их преобразованию в обычный матричный формат представления данных.
Типы данных 101 Для того чтобы представить себе экономию от хранения разреженных матриц, приведем пример 3.11. : —" :■• ....._....)..,. ■■ ■ --;:...-... - ; ; Пример 3.11. Разрежённая матрица ■. ■ ■%.?'■ ч *-*г,^Шш£= \ » а=еуе(100); » b=sparse(eye(100)) ; » whos Name Size Bytes Class a 100x100 80000 double array b 100x100 1604 sparse array Grand total is 10100 elements using 81604 bytes В разреженных матрицах могут храниться элементы только типа double. 3.1.5. Структуры и массивы структур (struct arrays) Структуры, или записи (в C++ и Java — struct, в Pascal — record), представляют собой тип данных, порожденный общепринятыми таблицами. Для таблиц характерны строки данных единого формата, определяемого заголовком таблицы. Каждая строка таблицы представлена последовательностью полей. Одноименные поля образуют колонки таблицы, в которых располагаются данные одинакового типа. Друг от друга поля отличаются идентификаторами, соответствующими заголовкам колонок таблицы. Таблицы широко используются в реляционных базах данных, они позволяют повысить эффективность представления данных в памяти ЭВМ. ускоряют обмен с файлами, повышают наглядность представления результатов работы многих программ. Представим себе простейшую таблицу с тремя колонками, содержащими сведения об авторах (табл. 3.3), которую мы хотим оформить в виде массива authors, включающего три структуры. Наименования колонок — полей структуры — продублированы на английском языке, т. к. в идентификаторах полей употребление русских букв запрещено. Таблица 3.3 Фамилия, И. О. (Name) Иванов И. И. ■ Петров П. П. Сидоров С. С. Возраст 31 32 33 (Age) Телефон (Phone) 11-11-11 22-22-22 33-33-33
102 Глава 3 Одним из способов формирования структуры является использование функции struct (пример 3.12), которая заполняет указанный элемент массива структур. Аргументами этой функции являются пары, содержащие имя поля и соотвегствующее значение. Вте предшествующие элементы массива структур формируются как поля с такими же наименованиями, значения которых заполнены пустыми матрицами 1x1. Очевидно, что в левой части оператора присваивания удобнее заполнить последнюю структуру массива, иначе изначально не будет создан массив нужного размера. Однако это вовсе необязательно, и в первый раз мы можем вызвать функцию struct для создания первого элемента массива структур. А потом добавлять последующие строки таблицы. Дело в том, что размер массивавсе равно будет изменяться в зависимости от длины значений, присваиваемых полям незаполненных ранее структур. Тем не менее, формирование массива структур целиком позволит избежать дополнительных затрат, возникающих при увеличении количества элементов. ; Пример 3,12. Формирование структуры . ^-. » authors(3)=struct('Name','Сидоров С.С.','Age',33,... 'Phone','33-33-33'),■ » who.3 Name Size- Bytes Class authors 1x3 440 struct array Grand total is 28 elements using 4 40 bytes Теперь можно заполнить пустые поля в двух предшествующих структурах, используя индексирование элементов массива и составные имена соответствующих полей: » authors(1),Name='Иванов И.И.'; » aut nors(1).Age=31; » authors(1).Phone='11-11-11' ; » authors(2).Name='Петров П.П.'; » authors(2).Age=32; » authors(2).Phone='22-22-22'; С помощью функции fieldnames можно получить информацию об именах полей указанной структуры: » f ieldnames(authors) ans = 'Name' 'Age' ' Phone-'
Типы данных 103 Однако для вывода содержимого полей приходится набирать имя каждой структуры — элемент соответствующего массива: » authors(1) ans = Name: 'Иванов И.И.' Age: 31 Phone: 41-11-11' » authors(2) ans = Name: 'Петров П.П. ' Age: 32 Phone: '22-22-22' » authors(3) ans = Name: 'Сидоров C.C.' Age: 33 Phone: '33-33-33' Второй способ, который требует существенно меньших затрат по набору исходных данных, использует групповое задание значений каждого поля в виде списка ячеек (термин ячейка поясняется в следующем разделе). Список ячеек заключается в фигурные скобки (пример 3.13). ; Пример 3.13. Список ячеек " !. ^^¾¾ '■■'- ; V.:. "Г. ::....:: ::....;: :....Ж:....:„Ш<т&$&Ж:. ,....*»«.:„: -.:-..,., • » authors-struct('Name',{'Иванов И. И.','Петров П. П.',... 'Сидоров С. С.'>,'Age',{31,32,33},'Phone', {'11-11-11', '22-22-22', ... '33-33-33'}); » v/hos Name Size Bytes Class authors 1x3 1058 struct array Grand total is 67 elements using 1058 bytes Может оказаться полезной и еще одна возможность сформировать массив структур, содержимое полей которых заполнено одинаковой строкой таблицы. Она достигается многократным размножением одной структуры с помощью функции repmat (от англ. repeat matrix — повторить матрицу): » authors=repmat(struct ('Name','Abe','Age',100,... 'Phone','00-00-00'),1,3);
104 Глава 3 Два последних аргумента функции repmat определяют первый и последний индексы формируемых структур. В существующем массиве структур легко добавить новое поле путем присвоения значения в любом элементе массива: » authors(2).gonorar=1500; К двум оставшимся записям автоматически добавится пате с именем gonorar, которое будет временно заполнено пустой матрицей размерности 1x1. Для удаления ненужного поля из всех записей используется функция rmf ield'. » authors = rmfield(authors,'gonorar'); В качестве значения какого-либо поля структуры может, в частности, выступать и массив. Тогда, чтобы добраться до конкретного значения в этом массиве, необходимо использовать два индекса — индекс структуры (например, d_s) в массиве структур и индекс конкретного элемента массива (например, if) в заданном поле: » у = riame_ms (i_s) .name_f (i_f) ; Здесь через names обозначено имя массива структур, а через name_f — имя поля в структуре. Как правило, в качестве индексов выступают либо конкретные числа, либо значения переменных, пробегающие в цикле тот или иной диапазон. Однако в некоторых задачах и имя массива, и имя поля может вычисляться программным путем. Тогда имя нужного компонента будет представлено неявно — как значение переменной символьного типа. В этом случае для доступа к значениям полей структуры необходимо использовать одну ИЗ функций — getf ield ИЛИ putf ield: » у - getLield(var_ms,i_s,var_f,i_f); >> putfield(var_ms,i_s,var_f,i_f, value); Параметр value здесь представляет значение, засылаемое в указанное поле. 3.1.6. Массивы ячеек (cell arrays) Числовые массивы состоят из элементов одного типа. Массивы структур в простейшем случае представляют набор строк таблицы, устроенной по единому формату (но в пределах одной записи содержимое полей может быть разного типа). И тот, и другой тип массивов был хорошо известен в системах программирования общего назначения. Однако в MATLAB появился совершенно новый тип массивов cell array, в которых каждый элемент может быть представлен значением любого типа, независимо от типа соседних элементов. Каждый такой элемент называют ячейкой (cell) по аналогии с электронными таблицами, где каждая клетка может содержать индивидуаль-
Типы данных 105 ное значение любого типа. Конечно, единообразные действия, которые производились для нормальных массивов (например, поиск максимального элемента, суммирование данных в столбце и т. п.), в массиве ячеек смысла не имеют. 3.1.7. Массивы указателей на функции (function handle arrays) Еще одним типом данных, заслуживающим внимания, является класс function_handle. С термином handle (произносится — хэндл) многие программисты сталкивались при работе с файлами при создании подпрограмм обработки событий в различных визуальных средах. Термин handle пока не получил единообразной трактовки в отечественной литературе. Под этим термином скрывается системный способ идентификации некоторых программных компонентов. Так, например, при работе с файлами вместо их идентификаторов (имен дисковых файлов или их полных спецификаций) в операторах обмена указывается тем или иным способом созданный handle. Им может быть конкретное число, которое операционная система присваивает открываемым файлам (int fi=open...), или указатель на блок управления файлом (см. в C++ описание типа file *fi;). Иногда этот термин именуют дескриптором (т. е. описателем). На наш взгляд, наиболее точно термину handle в русском языке соответствуют термины указатель или ссылка. Указатель на функцию (function handle) обеспечивает возможность доступа ко всей информации, необходимой для вычисления значения этой функции. Создается такой указатель (а по терминологии MATLAB — массив указателей) одним из двух следующим способов: » fjl=@funl; » f_h=atr2func('funl') В результате и той, и другой операции создается указатель f_h, который "смотрит" на функцию с именем funl. Первый вариант очень напоминает присвоение адреса переменной указателю соответствующего типа в C++ (int х; int *рх=&х;). Указатель f_h может быть передан в качестве аргумента другой функции: » у = integral(a,b,f_h); Для того чтобы функция integral могла воспользоваться значением функции funl{x), она использует системную процедуру feval: » z = feval(f_h,х) ; В фирменных руководствах утверждается, что использование указателей несколько повышает производительность интерпретатора при многократных обращениях к функции.
106 Глава 3 3.1.8. Логические массивы (logical arrays) Логические массивы (logical arrays) появляются в результате различных проверок, выполняемых с помощью стандартных функций — isietter (проверка на буквы), isspace (проверка на пробелы), isprime (проверка чисел на простоту) и др. (пример 3.14). Элементы логического массива занимают в памяти по одному байту, в котором может находиться либр 1 (логическая истина), либо о (логическая ложь). | Пример 3.14. Логический массив ■ ■"'!*3„*:''*"- Г' '«.v"". ] >> А=[2 3 4 5 6 7 8 9]; >> isprime(А) ans = 11010100 » who's Name Size Bytes Class A 1x8 64 double array ans 1x8 8 logical array Grand total .is 16 elements" using 72 bytes Другим способом создания логических массивов является использование логических констант true и false, эквивалентных однобайтовым 1 и 0: » x=[true false true] х = 10 1 » whos Name Size Bytes Class x 1x3 3 logical array Grand total is 3 elements using 3 bytes Для создания логических массивов, все элементы которых одновременно являются либо истиной, либо ложью, можно воспользоваться функциями true ИЛИ false: » x=true(2) х = 1 1 1 1 » y=true(2,3)
Типы данных 107 У = 1 1 1 1 » z=false([2 ■z = 0 0 0 0 » а=[5 б]; » v=false(a) V = 0 0 0 0 0 0 0 0 0 0 1 1 3]> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Единственный числовой аргумент в указанных функциях задает размерность квадратной матрицы: два числовых аргумента определяют количество строк и количество столбцов. Если в качестве аргумента выступает массив с целочисленными элементами, то их значения и определяют размерность создаваемого логического массива. 3.1.9. Создание массивов из данных разного типа Может быть, это и экзотика, но MATLAB 7 разрешает формировать символьные, числовые и логические массивы из комбинации данных разного типа. При этом система руководствуется определением типа результирующей матрицы по сочетаниям пар типов данных, представленным в табл. 3.4. Таблица 3.4 Тип char int single double logical char int single double logical char char char char-' Запрещено char int int int int char int single single single char int single double double Запрещено int s ingle double logical
108 Глава 3 Ниже приводится несколько примеров, заимствованных из справочных файлов. На наш взгляд, пользоваться такими возможностями не стоит (пример 3.15). : Пример 3.15. Экзотическое формирование массивов ..--.■ ., ^¾¾¾¾¾¾ •'! »% Пустой массив в списке значений игнорируется » А = [5.36; 7.01; []; 9.44] А = 5.3600 7.0100 9.4400 » % Сочетание данных типа single и double » х = [single(4.5) single(-2.8) pi 5.73*10Л300] x = 4.5000 -2.8000 3.1416 Inf » .%■ Сочетание данных типа int8 к double >> х = [int8(21) int8f-22) int8{23) pi 45/6] x = 21 -22 23 3 8 » % Сочетание данных типа char и double » x = ['А' 'В' 'С 68 69 70] x = ABCDEF » % Сочетание данных типа logical и double » х = [true false false pi sqrt(7)J x = 1.0000 0 0 3.1416 2.6458 3.2. Программа тестирования данных В состав пакета MATLAB включена программа explore, которая анализирует тип данных, указанных в качестве аргумента, и отображает значения всех переменных, относящихся к данному аргументу. Программа эта находится в каталоге ...\MATLAB7\extern\examples\mex, который надо сделать текущим перед ее запуском: » cd (' с: \MATLAB7\extern\examples\mex');. » str='Привет'; » explore(str);
Типы данных 109 Результат работы этого фрагмента таков: Name: prhs[0] Dimensions: 1x6 Class Name: char (.1,1) Привет Предыдущая версия этой программы из пакета MATLAB 6.5 в качестве значения параметра Name выводила имя своего аргумента. В новой версии при любом аргументе программа explore почему-то вьщает одно и то же. Один из разделов справочной системы предлагает опробовать программу на некотором наборе данных разного типа, и приводимый ниже протокол получен по этой рекомендации: » а=[]; % пустой массив » explore(а); Name: prhs[0] Dimensions: 0x0 Class Мате: double » а=[1 2 3J; % вектор-строка » explore(а) Wame: prhs[0] Dimensions: lx'3 С]ass Name: double (1.1) = 1 (1.2) = 2 U,3) = 3 » a=[l;2;3]; % вектор-столбец » explore(a); Uame: prhs.[0] Dimensions: 3x1 Class Name: double
110 Глава 3 (1,1) = 1 (2,1) = 2 (3,1) = 3 » а={1 2 3}; % массив ячеек » explore(а) ; Name: prhs.101 Dimensions: 1x3 Class Name: cell tota] num of cells = 3 Cell Element: (1/1) Dimensions: lxl Class Name: double (1,1) = 1 Cell Element: (1,2) Dimensions: lx1 Class Name: double (1,1) = 2 Cell Element: (1,3) Dimensions: lxl Class Name: double (1,1) =-3 » explore 12 3 Name: prhs[0] Dimensions: lxl Class Name: char (1,1) 1
Типы данных 111 Name: prhs[l] Dimensions: lxl Clas s Name: char (1,1) 2 Name : prhs[2] Dimensions: lxl Class Name: char (1,1) 3 » a=int8([l 2 3]); » explore(a); Name: prhs[0] Dimensions: 1x3 ciass Name: int8 (1.1) = 1 (1.2) = 2 (i,3) = 3 » a=sparse(eye(3)); » explore (a) ; Name: prhs[0] Dimensions: 3x3 Class Name: sparse (1.1) = 1 (2.2) = 1 (3.3) = 1 » explore (sttuet ('Name",'Иванов V\. И. ', 'Age', 31, 'Phone', '11-11-11')) ,- Name: prhs[Q] Dimensions: lxl Class Name: struct
112 Глава 3 (1,1).Name Dimensions: lxll Class Name: char (1,1) Иванов И. И. (1,1).Age Dimensions: lxl Class Name: double (1,1) = 31 (1,1).Phone Dijiiensions: 1x8 Class Name: char (1,1) 11-11-11 » explore(1, 2, 3) Name: prhs[0] Dimensions: lxl Class Name: double (1,1) = 1 Name: prhs[l] Dimensions: lxl Class Name: double (1,1) = 2 Name: prhs[2] Dimensions: lxl Class Name: double (1,1) = 3
Типы данных 113 3.3. Анализ типа данных и состояния элементов массивов Довольно многие системные и пользовательские функции допускают в качестве некоторых параметров данные разного типа. Очевидно, что обработка таких данных не всегда может вестись по единому алгоритму. Поэтому в системе MATLAB предусмотрен довольно большой набор функций, выполняющих анализ на принадлежность данных тому или иному классу и контролирующих состояние объектов (например, на начичие в числовом массиве нечисловых данных или бесконечных значений). Проверка на принадлежность объекта тому или иному типу данных осуществляется с помощью функции isa! a = isa(имя_объекта,'класс'); Функция isa возвращает логическую истину (a=i), если объект с указанным именем принадлежит заданному классу. В противном случае значением функции isa является логическая ложь (а=о). Список значений аргумента 'класс' приведен в табл. 3.5. Таблица 3.5 Класс Функция isa проверяет, является ли ее первый аргумент: char numeric logical intB uint8 intl6 uintl6 int32 uint32 int64 uint64 single double cell struct function handle- символьным массивом числовым массивом (целочисленным или вещественным) логическим массивом массивом однобайтовых целых чисел со знаком массивом однобайтовых целых чисел без знака массивом двухбайтовых целых чисел со знаком массивом двухбайтовых целых чисел без знака массивом четырехбайтовых целых чисел со знаком массивом четырехбайтовых целых чисел без знака массивом восьмибайтовых целых чисел со знаком массивом восьмибайтовых целых чисел без знака массивом вещественных чисел с одинарной точностью массивом вещественных чисел с удвоенной точностью массивом ячеек массивом структур массивом указателей на функции
114 Глава 3 В качестве аргумента 'класс' у функции isa может выступать нестандартный класс, объявленный пользователем. В справочных файлах такая возможность демонстрируется на объекте типа poiynom: polynom_obj = poiynom([1 0 -2 -5]); isa(polynom_obj, 'poiynom') ans = 1 Ко второй группе функций, анализирующих свойства своих аргументов, относятся более 30 процедур. Их единственным аргументом является имя объекта, значения компонентов которого подвергаются той или иной проверке. Размерность результата, возвращаемая любой из этих функций, совпадает с размерностью аргумента. Проверке подвергается каждый компонент аргумента, и если анализируемое свойство удовлетворяет предназначению функции, то в соответствующий элемент результата заносится логическая истина. В противном случае в соответствующий элемент результата заносится логическая ложь. Более подробно специфика некоторых функций обсуждается ниже. Функция isreai(q) проверяет, являются ли элементы массива q вещественными или комплексными числами (пример 3.16). Если хотя бы один элемент указанного массива содержит мнимую часть (даже равную нулю), то функция isreal возвращает логическую ложь. Если переменная х имеет вещественное значение, то y=compiex(x) представляет комплексное значение с нулевой мнимой частью. Но isreal (у) =о. Если аргументом функции isreal является массив ячеек, отдельные элементы которого — комплексные числа, то в возвращаемом векторе значений нулевые компоненты соответствуют комплексным ячейкам, а единичные компоненты — всем остальным (среди остальных компонентов массива могут быть и нечисловые ячейки). | Пример 3.1.6, Демонстрация райоть! функции isreal ()■..■; » qll, l}-'Text'; %■ строка » q{l,2}=3; %" число типа double » g{l,3}=magic(2); % массив 2x2 типа double » q{l,4}=l+i; % комплексное число » q{l,5}=isreal(pi); % логическое значение » q q = 'Text' [3] [2x2 double] [1.0000+ l.OOOOi] [1] » for j=l:5, a{j)=isreal(q{l,j}); end
Типы данных 115 » а а = 1110 1 Функция isnuraeric(q) проверяет, являются ли ее аргументы числовыми данными, в разряд которых причислены вещественные и комплексные значения (пример 3.17). А вот символы, строки, логические значения, структуры и массивы перечисленных данных к группе чисел не относятся. Для приведенного выше массива ячеек q эта проверка дает следующие результаты. j Пример 3.17. Демонстрация работы функции isnumeric() ■, ' » for 3=1:5, a(j)=isnumeric(q{l, j[); end » a a = 0 1110 Функция ischar(q) проверяет, являются ли ее аргументы символьными данными. Для приведенного выше массива ячеек q эта проверка дает результаты, представленные в примере 3.18. I Пример 3.18. Демонстрация работы функции ischar() » for j=l:5, a(j)=ischar(q{l,j}); end » а а = 1 о о о о Функция isiogicai(q) проверяет, являются ли ее аргументы данными логического типа. Для приведенного выше массива ячеек q эта проверка дает следующие результаты (пример 3.19). j Пример 3.19. Демонстрация работы функции Islogical () » fox j=l:5, a(j)=islogical(q{l,j}); end » a a - о о о о l
116 Глава 3 Функции iscell(q) и iscellstr(q) позволяют узнать, является ли аргумент q массивом ячеек и представлена ли каждая ячейка строкой (пример 3.20). I, Пример 3.20. Демонстрация работы функций iscell (): и iscellstr () ■&- w-:'r i » iscell(q) atis = 1 » iscellstr(q) ans = 0 С помощью функции isstruct можно убедиться, является ли ее аргумент структурой (пример 3.21). : Пример 3.21. Демонстрация работы функции isstruct () » a.fl='abc'; » a.f2=[0 1 2]; » a.f3=[{'abc,}/l0,l,2}]; » а а = fl: 'abc' f2: [0 1 2] f3: ('abc' [0] [1] [2]} » isstruct(a) ans = 1 Функция issparse(A) проверяет, является ли матрица а разреженной. Если это так. то функция возвращает логическую истину. С помощью функции isempty можно убедиться в том, что ее аргумент представлен пустым массивом (пример 3.22). | Пример3.22. Демонстрация работы функции isempty 6 ' ч-'у г ..''- >> х=П,- » is'empty'(x) ans = 1
Типы данных 117 Функции isfinite(A), isinf (А) и isnan(A) анализируют значения элементов вещественного массива а и выясняют, какие из них принадлежат к допустимому диапазону числовых значений (Finite — конечный), к бесконечным значениям (infinite — бесконечный), к неопределенным значениям (NaN — Not a Number) — пример 3.23. ;■ Пример 3^23. Демонстрация работы функций isf inite (), isinf () и ienan ()'Р 'i » х=[1 0 inf nan]; » y-l./x Warning: Divide by zero. У = 1 Inf 0 NaN » zf=isfinite(y) zf = 10 10 » zi=isinf(y) zi = 0 1 D 0 » zn=isnan(y) zn = 0 0 0 1 Для выделения букв в символьной строке или в символьном массиве можно воспользоваться функцией is letter (пример 3.24). ; Пример 3.24..Дёмонс1 рация работы функции is letter () Й: .*"•■*; i;w ^'i » x='alb2c3'; » isletter(x) ans = 10 10 10 >> y=I'al,;,b2';,c3'] У = al b2 c3
118 Глава 3 >> isletter(y) ans = 1. О 1 О 1 О Функция isprime(д) выясняет, какие элементы массива а являются простыми числами. Проверяемые числовые значения должны быть положительными целыми и не превосходить по величине 232. В противном случае функция isprime выдает сообщение об ошибке. К спорному моменту относится значение isprime (1)=0. Ряд математиков относит единицу к простым числам, т. к. она не имеет других делителей кроме 1 и самой себя. С помощью функции issorted(v) можно проверить, упорядочены ли по возрастанию компоненты числового или символьного вектора v (пример 3.25). Если первым аргументом этой функции является двумерный массив — issorted(A, "rows'), — то проверка упорядоченности распространяется на каждый столбец матрицы а. [Пример 3.25. Демонстрация работц функции issortedO v -- » а=[1 2 3 4 5]; » issorted(a) ans = 1 » b=[5 4 3 2 1]; » issorted(b) ans = 0 » c='abc'; '». issorted(c) .ans = 1 » d='bac'; » issorted(d) aris = 0 » e=[l 2 3; 2 3 4]
Типы данных 119 12 3 2 3 4 » issorted(е,'rows'] ans = 1 3.4. Редактирование массивов Массивы, сформированные вручную или полученные в результате вычислений, хранятся в рабочем пространстве (workspace). Любой из них или несколько одновременно могут быть подвергнуты коррекции с помощью Array Edilor (Редактор массивов). Последний вызывается двойным щелчком по имени массива в рабочем пространстве (рис. 3.2). Top/Bottom Split Left/Right Split Tile Maximize Float т ,>MATLAB File Edit View Graphics Debug Desktop Window Help Shcdcus .ilHawluAiJd .£|VVbflt-sr4ew v-'-trhspCCCf . is tf ® «s *'□ -F Мяте V | v«*J<t EBB IJOO.JOO) EBa ilZJ.4 5 6] «1 1 rjtfjyiftajjd Window ■-> A=(l 2 3; 4 5 fi] A - 12 3 (15 6 » B=[iaO;200I В = lDi) 200 » X ■■ l\ 1 СКИЖ double double jj .* X d riArra Editor - . L. i ?. ... У ■:- - T ..|ГТ *м a«ii [ - _J г- <=■ 1 э -J ±1 i i vl iool 3 6 7 If .of 11 '12 Ail HfilEI * X E Ш В ЁР]о] 2 Э . . I Рис. 3.2. Редактирование массивов А и В Для размещения двух или более массивов поле редактора можно разбить несколькими способами с помошыо управляющих кнопок: О Tile — в клетках матрицы; П Left/Right Split — в вертикальных колонках; 5 Зак 8W
120 Глава 3 О Top/Bottom Split — в горизонтальных полосках; О Float — друг за дружкой; О Maximize — текущая таблица занимает все поле. Для изменения значения элемента массива необходимо либо с помощью клавиш управления курсором, либо используя мышь, выделить нужную ячейку и набрать в ней новое значение. Ввод изменяемого числа завершается нажатием клавиши <Enter>. Новое значение немедленно отображается в соответствующей позиции колонки Value (Значение) в рабочем пространстве (рис. 3.3). -ДМАТЬАВ File Edit View. Graphics Debug Desktcp 'Window Help StotM: _'J How to Add И WioVs New t-i&rkspacB * x ■й ill © Вв©1*:Ы -||n.- J hiame '" j Veiue | Cibm Ше [I00;20] double El A [12 3,4 5 6] double Command Window» i> x » A=[l 2 3; 4 Ъ 6] ±_ A = 12 3 4 5 6 » B= [100:.2()0] E = _J 100 f ZOO ZJ ^1 Shirt | ЙArray Editor !й 1 * щ ш. О1 и i i i a,-i ll ll 2 2 4( ___J, W - \ - " 6i 1 7 ; : V S 10 и 12- Ia »![b~~4 _ _ _ - ] 'И ' Stoci:| ." ,-. ■«• V 3 - Г '" ±J ,.,..^1 ^^^■^M 1 J.. 'J- _4_ 5 6 7: "fi * ' ,00 zc ИПП 2 S 10 | il zU - — 3 : il - - ,i ► 1 1 Л Рис. 3.3. Изменение значения В (2) Окно с гем или иным массивом можно снять с якоря и перетащить на более удобное место. В этом случае к окну автоматически приклеивается меню (рис. 3.4). С помощью команды View | Numeric Array Format (Вид | Формат: числовой массив) можно выбрать подходящий формат отображения числовых данных. Команды меню Desktop (Рабочий стол) позволяют вновь поставить на якорь текущее окно или все окна-массивы, находящиеся в свободном плавании.
Типы данных 121 Замечание С помощью Array Editor (Редактор массивов) можно изменять векторы или матрицы. Массивы более высокой размерности в этом редакторе не обрабатываются. Гм] F^^^^^H File Edit f Vk n 2 3 4 s '6 '■ i i 20 7 I Bj 9. <l " 3W Graphics Debug Desktop Wind tumeric Array Format ► * short . 5oiJpOriciU'va! , shortE _ long longE longG hex ,„ bank rational ow ■ - n|x| Help I 6 — — •»■ - 3 "▼■ I ► I ' Рис. 3.4. Окно с массивом В, снятое с якоря
I
Глава 4 Программирование вычислительных процессов До сих пор мы использовали командное окно MATLAB в режиме диалога пользователя с системой. Пользователь набирал в текущей строке очередную команду и нажимал клавишу <Enter> — система выполняла соответствующее действие и, при необходимости, выдавала результат этого действия. Все набираемые команды повторялись в окне Command History (История команд) и запоминапись в специальном стеке, откуда могли извлекаться для повторного выполнения ранее набранных действий или для формирования похожих команд. Однако такой пошаговый режим хорош только для разового расчета. Даже повторение одной и той же вычислительной схемы с небольшой модификацией алгоритма или с изменением исходных данных в пошаговом режиме превращается в обременительное занятие. 4.1. Скрипты и функции В простейшем случае мы могли бы включить ту же самую цепочку команд в текстовый файл, записать его на диск, а затем вызвать и уже автоматически выполнить, не нажимая клавишу <Enter> после очередной команды. Подобного рода программы по терминологии MATLAB принято называть скриптами (scripts). В книгах некоторых российских авторов для их обозначения используют термин сценарий, хотя с этим словом ассоциируются совершенно другие понятия. Главной особенностью скриптов является то, что они работают только с переменными Workspace (Рабочее пространство). Скрипт может извлекать данные из файлов, запрашивать их у пользователя, обращаться к любым стандартным и нестандартным функциям. Несколько скриптов могут работать последовательно друг за другом, передавая данные следующему скрипту через общее рабочее пространство или запоминая промежуточные результаты в файлах. Однако отсутствие локальных переменных в скриптах затрудняет Создание цепочек программ из-за необходимости согласованного использования общих переменных. Скрипт может быть подготовлен в любом текстовом редакторе и записан в дисковый файл
124 Глава 4 с расширением т. Однако MATLAB располагает собственным редактором гп-файлов, который вызывается командой File | New | M-File (Файл | Создать | М-файл) — рис. 4.1. -Amatlab НПО File Edit Debug Desktop. Window Help _ _ Save Workspace As.., Orl+S GUI Ж Editor - Untitled* File Edit Tert СЫ1 Tools Debug Desktop Window Help d & a |"v Vsa ^ -• \&i« t. aia'!"ёia ib >» ж^р^з 1 a=l Z +у,с i=i:5 3 a=a'ri Д end 5 a Рис. 4.1. Окно редактора кода. Строки, набираемые в окне редактора, автоматически нумеруются. Это позволяет идентифицировать сообщения об ошибках набора, выдаваемых в командное окно. Обратите внимание на специфику набора строк программы. Если в языке С каждый оператор завершался точкой с запятой, то в языке MATLAB точка с запятой в конце оператора подавляет вывод результата. Вторая неожиданность — формат оператора цикла, который па С выглядел бы следующим образом: for(i=l; i<=5; i++) По аналогии с языками Fortran и Basic единичное приращение управляющей переменной цикла можно опускать (более полный формат MATLAB — for i=i:i:5). Наконец, еще одно наследие Basic, в.котором тело цикла for завершается оператором next. В MATLAB нет операторных скобок, таких как в С и Pascal, в которые заключаются операторы, образующие тело цикла. Поэтому для определения его конца необходимо использовать оператор end. Этим же оператором в MATLAB завершаются и другие структурные единицы (if, switch, try, while). Наконец, 5-я строка включена в текст программы только для того, чтобы увидеть результат вычисления факториала. Конечно, в MATLAB имеются и другие средства вывода результатов, но мы воспользовались простейшим вариантом отображения значения переменной. шли вэ ш в е [□
Программирование вычислительных процессов 125 Для запуска фрагмента, представленного на рис. 4.1, необходимо выполнить команду Run (Запуск) в меню Debug (Отладка) или нажать клавишу <F5>. Результаты его работы появятся в командном окне, т. к. никаких других окон для визуализации результатов расчета мы не предусмотрели: а = 120 » Для запоминания программы, набранной в окне редактора кода, можно воспользоваться командой File | Save As (Файл | Сохранить как). Пример, приведенный выше, мы запомнили под именем fact5. Для его повторного выполнения в текущей строке командного окна достаточно набрать имя файла: » facts а = 120 » Более удобной разновидностью гп-файлоп являются функции, первой строкой которых является заголовок, использующий оператор function. В отличие от скриптов, функции могут получать исходные данные в виде списка входных параметров и возвращать результаты своей работы также в виде списка выходных параметров. Если некоторые переменные Workspace (Рабочее пространство) объявлены глобальными (оператор global) и такое объявление global с указанием имен общих переменных присутствует в теле функции, то функция имеет доступ к указанным переменным. Эта идея в явном виде заимствована из Fortran, хотя там был разработан более гибкий механизм блоков обшей памяти (оператор соммоь?), позволявший общающимся модулям называть общие переменные по-разному, сохраняя их порядок и тип данных в общих блоках. И только имена блоков у них должны были называться одинаково. Одной из самых важных особенностей функций является аппарат локальных переменных. Все переменные, появляющиеся в теле функции, за исключением глобальных переменных, входных и выходных параметров, считаются локальными. Они образуют локальное рабочее пространство и доступны только в теле породившей их функции, и никакие, скрипты или другие функции воспользоваться ими не могут. Это развязывает руки при написании программ-функций, т. к. имена локальных переменных не надо ни с кем согласовывать. При написании программ-функций требуется, чтобы имя m-фаила, в котором запоминается программа, обязательно совпадало с именем функции. Пример более универсальной программы, вычисляющей п!, может быть на-
126 Глава 4 писан так, как представлено в примере 4.1, и должен быть сохранен под именем factn.m. I Пример4.1. Функция вычисления факториала €№.;■„■. ■}»'?. -^^Щ^.'-Щ function y=factn(n) k=l; for<i=l:n) k=k~i; end y=k; Для вычисления 5! достаточно набрать в текущей строке команду: »k-factn(5) к = 120 » В любом m-файле, подобно языку C++, можно описать несколько функций. Самая первая из них обладает тем преимуществом, что ее можно вызвать извне. Все остальные функции считаются внутренними и доступны только в рамках данного m-файла. Их принято называть подфункциями (subfunctions). Система MATLAB выполняет m-файлы, как правило, в режиме интерпретации, что существенно снижает скорость решения задач по сравнению с возможностями компилирующих систем. С целью повышения производительности MATLAB в режиме интерпретации использует промежуточный псевдокод (так называемый p-code — от англ. pseudocode). Происходит такая замена исходного текста при первом обращении к скрипту или функции. Псевдокод позволяет свести к минимуму работу по синтаксическому разбору многократно выполняющихся операторов программы. Особенно это важно при повторных вызовах функций. Псевдокод остается в памяти либо до конца сеанса, либо до очистки оперативной памяти с помощью одной из команд: Clear имя_функции % удаление конкретного, псевдокода clear functions % удаление псевдокодов всех функций clear all % удаление всех функций и переменных Любой m-файл может быть превращен в псевдокод с помощью процедуры pcode: pcode имя_п>-файла
Программирование вычислительных процессов ' 127 Результатом ее работы является двоичный файл с тем же именем и расширением р. Такая предварительная замена исходного текста позволит сократить время обработки файла при его первоначальной загрузке, а также сохранить в тайне исходный текст алгоритма. 4.2. Специфика выполнения операций При составлении алгебраических выражений MATLAB разрешает использование традиционных знаков арифметических операций и символов специальных операций, полный список которых приведен в табл. 2.3. Но даже такие традиционные операции, как сложение, в выражениях MATLAB выполняются особым способом. Самым привычным является сложение скалярных величин (т. е. массивов размерности 1x1), соответствующее аналогичному действию в большинстве алгоритмических языков. Если обоими операндами являются массивы одинаковой размерности, то осуществляется покомпонентное сложение элементов с одинаковыми индексами. Такой подход в свое время наблюдался в ранних версиях Basic, включавшего операторы типа мат а=в+с. Однако если в MATLAB к массиву любой размерности добавляется скалярная величина, то она добавляется к каждому элементу массива. По сути дела, добавляемое скалярное значение преобразуется в массив такой же размерности, что и первое слагаемое (аналог приведения типов в выражениях с разнокалиберными операндами), и каждый элемент расширенного массива равен этому значению. Попытку сложить массивы разной размерности (за исключением случая, когда один из операндов — массив 1x1) система пресекает с выдачей соответствующего сообщения об ошибке. Аналогичное приведение типов выполняется для большинства операций, когда одним из операндов является массив, а вторым — скаляр. При выполнении логических операций над числами действует соглашение, принятое в С, — ненулевые значения рассматриваются как истина, а нулевые как ложь. В качестве небольшой странности языка MATLAB отметим, что такая распространенная логическая операция, как исключающее ИЛИ, здесь подключена в виде функции хог (х, у). • 4.3. Синтаксис операторов MATLAB Входной язык MATLAB насчитывает всего 9 операторов, использующих 14 служебных слов. Соответствующие синтаксические конструкции приведены в.табл. 4.1.
128 Глава 4 Таблица 4.1 № Формат оператора Пояснение ■\ var = expr 2 if условие_1 операторы_1 [elself условие__2 операторы_2 elself услозие_3 операторы_3 else операторы ] end 3 switch expr case vail олераторы_1 case val2 операторы_2 [ othervise операторы] end 4 for var=el:[e2:]eJ операторы end 5 while условие операторы end 6 try олераторы_1 catch операторы_2- end 7 break Оператор присваивания. Вычисляет значения выражения expr и заносит результаты вычислений в переменную var Условный оператор. Если справедливо усло- вие_1, то выполняется группа операторы__1, если справедливо условие_2. то выполняется группа операторы_2,... Если все указанные условия оказываются ложными, то выполняются операторы, расположенные между else и end Переключатель по значению выражения ехрг. Если оно совпадает с величиной vail, то выполняется группа операторы_1, если оно совпадаете величиной val2, то выполняется группа операторы^, ... Если значение ехрг не совпадает ни с одной из перечисленных величин, то выполняются операторы, расположенные между othervise и end Цикл типа арифметической прогрессии, в котором переменная var при каждом повторении тела цикла изменяется от начального значения el с шагом е2 до конечного значения еЗ Цикл с предусловием, повторяющийся до тех пор, пока истинно указанное условие Попытка выполнить группу операторы_1. При условии, что в результате их выполнения возникает исключительная ситуация, управление передается группе опера торы_2. (обработка сбойных ситуаций). Если ошибка не возникла, то группа опера- торы_2 не выполняется Досрочный выход из управляющих конструкций типа for, while, switch, try-catch
Программирование вычислительных процессов 129 Таблица 4.1 (окончание) № Формат оператора Пояснение 8 function f 1 Заголовок функции function (*li *2,... — входные параметры; yl, у2, ... — f2 {xl, х2,...) выходные параметры) function y=f3(xl,x2,...) function [yl,y2, . ..]=f<l(xl,x2, 9 return Досрочным выход из тела функции Для ярых поклонников Дейкстры отметим, что язык MATLAB не содержит оператора goto. В связи с этим в текстах m-файлов отсутствуют метки операторов. Для идентификации строк, в которых возникают аварийные ситуации, используются внутренние номера, присваиваемые системой автоматически. Комментарии в m-файлах начинаются с символа %. Они могут располагаться с начала строки или находиться правее любого оператора. Однако при оформлении m-файлов начальные комментарии выполняют особую роль. Первая группа строк с подряд идущими комментариями до пустой строки образует текст, выдаваемый в командном окне по команде help с именем m-файла. Добавим, например, к приводившейся выше программе вычисления 5! комментарий (пример 4.2) и сохраним файл fact5.m. i Пример 4.2. Комментарий-подсказка % Эта программа находит 5! а=1; for 1=1:5. S=a*i; end .а. Если в текущей строке командного окна обратиться за помощью к этой явно несистемной функции, то MATLAB выдаст начальный комментарий: » help fact5 Эта программа находит 5!
130 Глава 4 Обратите внимание, насколько тщательно оформляются системные т- файлы. В качестве примера мы выбрали программу определения корней полинома roois.m, расположенную в каталоге c:\MATLAB7\toolbox\MATLAB\ polyfun: function г = roots(с) %ROOTS Find polynomial roots. % ROOTS(С) computes the roots of the polynomial vjhose coefficients % are the elements of the vector C. If С has N+l components, % the polynomial is С(1)*ХЛМ + ... + C(W)*X + C(N-H). % % Class support for input c: % float: double, single % % See also POLY, RESIDUE, FZERO. % J.N. Little 3-17-86 % Copyright 1984-2004 The MathWorks, Inc. :¾ $Revision: 5.12.4.2 $ SDate: 2004/03/02 21:48:0b $ % ROOTS finds the eigenvalues of the associated companion matrix. if size(c,l)>l S size(c,2)>l error ('MATLAB:roots:NonVectorInput', 'Input must be a vector.') end с = с (:) . ■ ; n = size(с,2); r = zeros(0,1,class (c) ) ; inz = find(c>; if j sempty(inz), % All elements are zero return end %■ Strip leading zeros and throw away. 8 Scrip trailing zeros, but remember them as roots at zero. nnz = length(inz); с = с 1inz(]):inz(nnz)); r = zeros (n-inz (nnz) , 1};
Программирование вычислительных процессов 131 % Polynomial roots via a companion matrix n = length(с); if n > 1 a = diag (ones (l,n-2-) ,-1} ; a(l,:) = -c(2:n) ./ c(l); r = [r;eig(a)] ; end Справка, выдаваемая системой в командное окно, имеет вид: » help roots- ROOTS Find, polynomial roots. ROOTS(C) computes the roots of the polynomial whose coefficients are' the elements of the vector C. If С has N+l components, the polynomial is С(1)*ХЛЫ +...+ C(N)*X + С(N+l). Class support for input c: float: double, single See also POLY, RESIDUE, FZERO. Как видите, в выдаваемом кадре помощи могут находиться пустые строки, соответствующие пустым комментариям (т. е. строкам, содержащим единственный символ %). Обратите внимание на то, что функция roots может работать не только с обычными данными типа double, но и с коэффициентами одинарной точности (типа single). Комментарий в строке, начиная с символа %, является не единственной возможностью для включения пояснений в текст программы. Мы уже упоминали, что текст, расположенный в строке правее символов переноса (три точки), тоже воспринимается как комментарий. Во входном языке MATLAB 7 появилась возможность включения многострочиого комментария. Ему обязательно должна предшествовать строка, содержащая только два символа — % {. Признаком конца многострочного комментария является строка, содержащая также два символа — %}; %( Первая строка комментария Вторая строка комментария %}
132 Глава 4 Многострочный комментарий может включать в себя вложенный много- строчный комментарий. С помощью признаков начала и конца многострочного комментария можно отключать фрагменты программы во время ее отладки. В арифметических выражениях помимо операндов-массивов допустимо смешение типов данных. Например, к числовому значению можно прибавить значение типа char. MATLAB заменит символьное значение его числовым ASCII-кодом и выполнит предписанное действие, несмотря на кажущуюся несуразность такой операции: » х=5+'а' х = 102 Множественное присваивание, допустимое во многих языках программирования, в MATLAB запрещено: » а=Ь=2; ??? Error: Assignment statements cannot produce a result. » whos » Зато набрать в одной строке несколько операторов присваивания, разделяя их запятыми или точками с запятыми, не возбраняется (пример 4.3). ! Пример 4.3. Оператор присваивания :■«&;:, ■*••-■-- «*-Ц ..-' ' \г ■-.. '"■ ^,,. ё » х=2; у=3; » х X = 2 » У У = 3 » х=2, у=3 х = 2 У = 3 В условных операторах некоторый протест со стороны пользователей может вызвать возможность сравнения комплексных чисел. С точки зрения математики комплексные данные можно сравнивать либо на равенство, либо на
Программирование вычислительных процессов 133 неравенство. Это соответствует и геометрическому представлению комплексных чисел как точек на плоскости: координата х совпадает с вещественной частью числа, а координата у — с мнимой. Но никому не приходит в голову утверждать, что точка (10, 0) больше, чем точка (5, 4). Наиболее естественные отношения двух точек — одна точка находится левее или правее другой, расположена выше или ниже. A MATLAB при сравнении комплексных чисел допускает использование операции отношения "больше", "меньше" и сопоставляет при этом только вещественные части. ' Большинство операторов языка MATLAB напоминает аналогичные конструкции языка C++. Одна из немногих особенностей — завершение управляющих конструкций оператором end — вряд ли смутит программистов, освоивших даже базовые операторы языка С. Наиболее существенные детали связаны с программированием функций, допускающих переменное число аргументов, среди которых могут встречаться массивы, и четкое разделение параметров на входные и выходные. Этим особенностям и специфике передачи параметров разного типа мы посвятим отдельный раздел. 4.4. Ввод числовых и символьных данных Простейший способ ввода числовой и символьной информации, набираемой на клавиатуре, использует функцию input. Она допускает два формата обращения, первый из которых: х = input['приглашение') В ответ на приглашение, выданное программой, пользователь может набрать требуемое значение или ввести выражение, величина которого будет подсчитана с учетом текущего состояния переменных рабочего пространства и возвращена в качестве значения функции. Если пользователь в ответ на приглашение нажимает только клавишу <Enter>, то функция возвращает пустой массив типа double размером 0x0. Обратите внимание на то, что текст приглашения выдается в начале следующей строки. Если вы не хотите набирать вводимую информацию вплотную к подсказке, то можно предварительно нажать клавишу <Пробел> или переместить курсор соответствующей клавишей-стрелкой. А можно предусмотреть дополнительный пробел в тексте приглашения. Второй формат обращения к функции input: имеет вид: х = input('приглашение','s') В этом случае текст, набираемый пользователем, рассматривается как строка символов, которая и возвращается в качестве значения функции. В обоих случаях текст приглашения может содержать символы \п, управляющие пе-
134 Глава 4 реводом курсора в начало следующей строки. Это обеспечивает, в случае необходимости, вывод приглашений, состоящих из нескольких строк. 4.5. Вывод результатов вычислений Для вывода значения выражения, в частном случае которого может быть имя любой переменной, достаточно не набрать после него символ "точка с запятой", подавляющий выдачу результата. В других случаях можно прибегнуть к функции disp (от англ. display — отобразить), которая отличается от автоматического вывода только тем, что не выводит имя отображаемого значения — имя переменной, которой присваивается результат вычислений, или имя системной переменной ans: disp(выражение) В частном случае аргументом функции disp может быть строка, заключенная в одинарные кавычки. Функциями error или warning можно воспользоваться дли выдачи сообщения об ошибке или предупреждения. Их основным аргументом является текст сообщения, после вывода которого работа программы будет либо завершена (использована функция error), либо продолжена (использована ФУНКЦИЯ warning) — Пример 4.4. I Пример 4.4. Предупреждение и сообщение об ошибке » wa г ning (' Предупреждение ! ') Warning: Предупреждение ! >> error('Ошибка'j ??? Ошибка Вообще говоря, функция warning обладает гораздо более широкими возможностями и напоминает функцию cprirmf в языке C++. Ее общий формат таков: warning('name_w■,■format', список} Строка name_w используется в качестве идентификатора группы сообщений. При необходимости вывод всех сообщений одной группы можно заблокировать, обратившись к процедуре warning следующим образом: warning('off,'name_w') При этом не понадобится удалять все строки, содержащие сообщения данной группы.
Программирование вычислительных процессов 135 Если снова понадобится включить эти сообщения, то вызывается процедура warning с параметром on: warning ('on','name_w') Строка format используется для форматных преобразований элементов выводного списка, и ее запись в точности повторяет форматные спецификации языка C++: warning Сqq:','x=%d y=%8.4f' ,к,у) Более подробно все форматные преобразования описаны в функции sprintf. 4.6. Типы функций Существует несколько разновидностей m-функций. В разд. 4.1 мы познакомились с головными функциями, имена которых совпадают с именами т- файлов. В фирменной документации они фигурируют под названием "первичные М-файлы" (Primary M-File Functions). К ним можно обращаться из других функций или из строк Command Window (Окно команд), передавать им параметры. Характерной особенностью m-функций является наличие индивидуального рабочего пространства — механизма локальных переменных. Наряду с последними, пг-фуикции могут использовать переменные из других рабочих пространств, где эти общие переменные объявлены как глобальные. Вторую разновидность m-функций составляют подфункции (subfunctions), описания которых расположены в m-файле вслед за головной функцией. Подфункции т-файла не могут быть вызваны извне. Это своего рода функции внутреннего пользования. Они могут общаться между собой в пределах т-файла и обращаться к другим головным функциям, расположенным в других т-файлах. Цепочку вызовов подфункций инициирует головная функция т-файла. В предыдущих версиях MATLAB преобладала идеология, близкая к языку С, в результате которой каждая функция выступала в роли отдельного кирпичика — вложения функций друг в друга не допускались. Седьмая версия сделала шаг навстречу языку Pascal и разрешила использование вложенных функций: function yl=fl(pl,p2) function y2=f2(xrz) S вложена в функцию fl function y3=f3.(a,b) % вложена в функцию £2
136 Глава 4 end S конец функции f3 end t- конец функции f 2 end % конец функции f1 При вызове вложенных функций соблюдается общепринятое правило: к вложенной функции может обращаться только непосредственно окаймляющая ее функция. В приведенном выше примере функция fi может вызвать функцию f 2-, но не может напрямую обратиться к функции f з. Вообще говоря, внятного объяснения по поводу преимуществ вложенных функций авторы MATLAB 7 не дали. До сих пор идеи, заложенные в Fortran, не признававшем вложенных функций, и в Algol, разрешавшем вложения, сосуществовали параллельно. В MATLAB 7 было решено их объединить, но пока не ясно, зачем. Кроме вложенных (nested functions) в 7-й версии появились анонимные (anonymous functions) функции. По сути дела, у этих функций нет собственного имени, вместо которого используется указатель функции. Формат их объявления таков: h_F=@(список_параметров) формула Очевидно, что описания функций такого типа имеют смысл при работе с достаточно простыми формулами. Например, анонимная функция возведения в квадрат с указателем sqr может быть описана и использована следующим образом: » sqr = @(х) х.Л2; » sqr([l 2 3]) ans = 14 9 С точки зрения пользователя эта анонимная функция ничем не отличается от обычной функции с именем sqr. Однако мы допускаем, что реализация анонимной функции более эффективна. Указатель на анонимную функцию может быть передан другим функциям в качестве параметра. Например, мы можем обратиться к функции вычисления определенного интеграла от х2 на интервале от о до 1 следующим образом: » quad(sqr, 0, 1) ans = 0.3333 Часть m-функций может быть помешена в каталог со специальным именем private. Эти функции будут доступны только из родительского каталога, со-
Программирование вычислительных процессов 137 держащего каталог private. Функции, хранящиеся в этом каталоге, считаются частными (private functions). Основное их назначение — заменить некоторые системные функции одноименными пользовательскими. MATLAB начинает поиск вызываемых функций с каталога private, поэтому они вызываются в первую очередь. Наконец, следует упомянуть еще об одной группе функций, для которых в литературе используется не очень удачный термин — перегружаемые функции (overloaded functions). В объектно-ориентированном программировании широко используется возможность определять несколько функций с одинаковыми именами, которые отличаются друг от друга либо количеством параметров, либо их типами, либо типом возвращаемого значения. Компилятор анализирует очередное обращение к функции и вызывает ту из них, которая соответствует шаблону вызова. 4.7. Параметры функций Почти все универсальные алгоритмические языки объединяют входные и выходные аргументы функций в общие скобки и возвращают в качестве своего значения единственный результат, обычно присваиваемый имени функции. Большинство алгоритмических языков использует позиционный принцип задания аргументов — каждый аргумент расположен на фиксированном месте в списке параметров. Только некоторые системы (в частности, ассемблер) наряду с позиционными аргументами позволяют использовать ключевой способ задания параметров в форме имя=значение. Ключевые параметры всегда располагаются вслед за списком позиционных аргументов и могут следовать в любом порядке. Вызывающая функция обычно передает свои параметры через стек, помещая туда значения или адреса соответствующих аргументов. Существуют два принципиально разных способа записи параметров в стек — один из них в стиле С (модификатор edeel) первым заносит в стек последний аргумент списка, а второй в стиле языка Pascal (модификатор pascal) первым заносит в стек первый аргумент списка. Обычно с этим приходится считаться в тех случаях, когда фрагменты программы реализованы в разных системах программирования. Для функций, допускающих переменное число параметров, программист или система программирования наряду с фактическими аргументами функций должны помещать в стек либо количество передаваемых параметров, либо завершать их список обусловленным признаком конца. В языке MATLAB входные и выходные аргументы функций четко разделены. Все входные параметры используют только позиционный принцип и задаются в круглых скобках после имени функций. Все выходные параметры объявляются как массив результатов и в операторах присваивания обычно записываются в квадратных скобках. Программистам, работающим на языке
138 Глава 4 C++, известно, что иногда функции могут иметь переменное число параметров (список формальных аргументов в заголовке функции завершается многоточием), и для создания такого рода программ используются специальные средства — функции (точнее, макроопределения) vastart, vaend, V3_arg, va_iist. Нечто похожее имеется и в языке MATLAB. Хотя переменное число параметров, как входных, так и выходных для m-файлов, скорее, является правилом, нежели исключением. MATLAB упаковывает все входные параметры в массив ячеек с именем varargin и запоминает количество передаваемых функции аргументов в глобальной переменной nargin. Функция, возвращающая переменное число значений, обычно начинается с заголовка: function [varargout] = имя__функции (аргументы) Это означает, что результаты работы функции должны присваиваться компонентам массива ячеек varargout. К. таким образом определенной функции можно обращаться с разным количеством выходных параметров: Iyl,у2,уЗ1 = имя_функции(аргументы) [zl,z2] = имя_функции(аргументы) wl = &1мн_фу'1кций (аргументы) В первом случае переменной yl будет присвоено значение ячейки varargoutп}, переменной у2 — значение ячейки varargout{2}, переменной уз — значение ячейки varargout{3}. Во втором случае будут использованы значения первых двух ячеек, в третьем случае — единственное значение первой ячейки массива varargout. Чтобы функция вычисляла только требуемое количество результатов, ей сообщают в глобальной переменной nargout фактическое число запрашиваемых данных. Для контроля за допустимым количеством входных и выходных аргументов m-функции могут использовать функции nargchk И nargoutchk: msg = nargchk(min, max, nargin); msg = nargoutchk(min, max, nargout); Обе функции формируют сообщение msg о недопустимом числе входных или выходных параметров, которое можно вывести с помощью функции error (msg). Если количество параметров принадлежит диапазону |min, max], то сообщение msg представлено пустой строкой и сообщения об ошибке не последует. Продемонстрируем использование описанных глобальных переменных на примерах, которые мы заимствовали из файлов помощи, но слегка модифицировали в сторону упрощения. •f
Программирование вычислительных процессов 139 Функция polyline.m получает массив переменной длины с координатами точек (xi,yi), (х2,у2) и т.д. и строит ломаную линию, соединяющую эти точки (пример 4.5). ! '■ '" '"""" 1F'";""" :"~ """v' "■•■■••' : ; Пример 4.5. Построение ломаной линии -.?■ ■ ■-;. . л ^. „. *■■>-. ^ -.; ; : '. :^:::..;...;;л: :.:..:;;л..Л д= .?..:&£ .■:; ,^шж&з.л:::гк1&:.:я:^..к; function polyline(varargin) for k=l:length(varargin) x(k)=varargin{k)(1) ; y(k)=varargin{k)(2) ; end axis ([nun (x) raax(x) min(y) max(y]]) plot (x, y) Результат обращения к этой функции с шестью следующими точками: » polyline ([2 3], [1 5], [4 8], [6 5], [4 2], [2 3]) приведен на рис. 4.2. Рис. 4.2. Полигон из 6 точек Результат обращения к этой же функции с другим количеством точек: polyline([-1 0],[3 -5], [4 2],[1 1]) приведен на рис. 4.3. Функция array2vec получает массив размерности лх2, первый столбец которого содержит координаты xi, х2, ..., а второй — координаты yi, у2, ... Задача функции разнести строки матрицы по выходным векторам, содер-
140 Глава 4 жатим координаты соответствующих точек— (xi,yi), (х2,у2),... (пример 4.6). Рис. 4.3. Ломаная линия из 4 точек [Пример, 4.6. Передача.аргументов функции . ; ;. - | function [varargout] = array2vec(a) for k=l:nargout varargout{k}=a(k,:); end Результат двух последовательных обращений с разным количеством выходных параметров приведен ниже: » а1={1 2; 3 4; 5 б; 7 8; 9 1С; 11 12); » [pi p2]=array2vec(al) pi = [1] [2] р2 = [3] £4] » [ql q2 q3 q4 q5]=array2vec(al) ql = [1] [2] q2 = [3] [4] q3 = [S] [61
Программирование вычислительных процессов 141 q4 = [7] Ф - [9] » whos Name al pi p2 ql q2 q3 q4 q5 [8] [10] Sizi 6x2 1x2 1x2 1x2 1x2 1x2 1x2 1x2 Bytes 816 136 136 136 136 136 136 136 Class cell cell cell cell cell cell cell cell array array array array array array array array Если в качестве входного параметра передать обычный числовой массив, то результатом работы той же функции будут обычные числовые векторы: » al=[l 2; 3 4; 5 6; 7 8} 9 10; 11 12]; » [pi p2]=array2vec(al) р] = 1 2 р2 = 3 4 » [ql qZ q3 q4 q5]=array2vec(al) ql = 1 2 q2 = q3 q4 = q5 = 10 >> whos Name al pl Size 6x2 1x2 Bytes Class 96 double array 16 double array
142 Глава 4 Р2 qi q2 q3 q4 q5 1x2 1x2 1x2 1x2 1x2 1x2 16 double array 16 double array 16 double array 16 double array 16 double array 16 double array Библиотека раздела string.h в системе программирования Borland C++ включает функцию strtok(str, del), с помощью которой осуществляется выделение лексем в строке str. Второй аргумент этой функции содержит набор символов, отделяющих одну лексему от другой. Например, при записи дат могут использоваться такие разделители, как пробелы ('Март 14 1972'), Дефисы ('Март-14-1972'), ПрЯМЫе СЛЭШИ ('Март/14/1972'). ФуНК- ция strtokfdate," -/") возвращает указатель на первую обнаруженную лексему и заносит пулевой код на место символа-разделителя. Это позволяет обработать найденную лексему как строку. Вторая и следующие лексемы выделяются этой же функцией, если в качестве ее первого аргумента задается указатель hull. Аналогичная функция с таким же названием содержится в каталоге MATLAB7\toolbox\MATLAB\strfun. В отличие от своего аналога, функция strtok.m умеет работать с одним или двумя аргументами, а в качестве результата возвращать (если попросят) две строки — найденную лексему и оставшуюся часть строки. Она активно использует глобальные переменные nargin, nargout, и когда к ней обращаются с единственным аргументом string, то в качестве разделителей использует так называемые белые пробелы— символы ASCII с кодами 9, 10, И, 12, 13 и 32. В примере 4.7 приводится текст этой функции, в котором комментарии переведены на русский язык и добавлены некоторые пояснения. I Пример 4.7. Функция strtok function [token, remainder] = strtok(string, delimiters) % STRTOK находит лексемы (token) в строке string. % STRTOK(S) возвращает первую лексему в строке S, завершающуюся % "бельм пробелом". Лидирующие пробелы игнорируются «■ %■ STRTOK(S,D) возвращает первую лексему, завершающуюся одним %- яз. симеолов, заданных в D. Лидирующие разделители игнорируются % % [T,R] = STRTOK(...) возвращает остаток исходной строки % Если лексема в 8 не найдена, то R равно пустой строке, a T=S %. if nargirKl, error('Не хватает входных параметров'); end
Программирование вычислительных процессов 143 token = []; remainder = []; len = length(string); if len = б return end if (nargin == 1) % Если входной аргумент один delimiters = [9:13 32]; £■ Коды "белых пробелов" end i = 1; % Пропуск лидирующих разделителей while (any(string(i) == delimiters)) i = i + 1; if (i > len), return, end end start = i; % Цикл до появления первого разделителя while (-any(string(i) =-delimiters)) i = i + 1; if (i > len), break, end end finish = i - l; token = string{start:finish); if (nargout =- 2) % Если задам второй выходной аргумент remainder = string (finish + 1: length (string) ) ,- end Вообще говоря, nargin и nargout являются не глобальными переменными, а функциями. К ним можно обратиться, задав в качестве аргумента имя т- функции. И тогда они возвращают количество входных и выходных параметров, указанных в заголовке функции: » nargin{'strtok') ans = ■2 » -nargout (' strtok') ans = 2 Вы уже обратили внимание на то, что функции с фиксированным числом входных или выходных параметров вовсе не обязаны прибегать к услугам массивов varargin и varargout. Однако когда число параметров может быть
144 Глава 4 переменным, то их использование способно существенно упростить процесс программирования. Очень изящно смотрится пример функции построения графиков, которой можно передать любой набор свойств и значений объекта типа Line: function myplot(х,varargin) plot{x,varargin{:}) К ней, например, можно обратиться с набором следующих аргументов: myplot(sin(0:.1:1),'color',[.5 .7 .3],'linestyle',':') И тогда в массиве varargin система сформирует четыре ячейки, элементами которых будут строка с именем свойства color, массив RGB-составляющих .[.5 .1 .3], строка с именем свойства linestyle и символ :, управляющий стилем линии. А в самой функции myplot не нужно прилагать никаких усилий по распаковке массива varargin и анализу его элементов. Массивы varargin и varargout могут появляться в заголовках функций в комбинации с обычными формальными параметрами, однако подобно ключевым параметрам их следует располагать в конце списка: function [yl,y2] = funl(xl,x2,varargin) function [yl, у2, varargout] = fun2{xl,х2,хЗ,х4) 4.8. Функции evalw feval MATLAB предлагает пользователю две системные функции eval и feval, прямых аналогов которым нет ни в одной системе программирования компилирующего типа. Главным аргументом функции eval (от англ. evaluation — вычисление) является строка, представленная любым допустимым выражением MATLAB или командой вызова известного системе m-файла. Функция eval исполняет (интерпретирует) эту строку, как если бы она была набрана в командном окне. Так можно вычислить формируемое во время работы программы выражение, исполнить функцию, введенную пользователем по запросу приложения. Наиболее распространенными форматами вызова функции eval являются: eval (stri) evai(st.rl,str2) [yl,y2,...] = eval('fun(xl,x2,...)') Для формирования выполняемой строки можно использовать операцию конкатенации строк, преобразования числовых параметров в символьный формат (int2str) и многое другое.
Программирование вычислительных процессов 145 В справочной документации приводится редкий по изяществу фрагмент, формирующий в цикле 12 магических квадратов с именами mi, М2, ..., М12 (пример 4.8). I Пример 4,8. Формирование 12:мат.чфских;кв'адр]^гоВ'^^ » --^У4 ^¾¾^¾ for n = 1:12 magic_str = ['М', int2str(n),' = magic(п)']; eval(magic_str) end Вторая необязательная строка str2 в списке параметров функции eval задает действия, которые нужно выполнить, если во время исполнения stri возникла ошибочная ситуация. В тестовом примере showdemo.m, содержащем всего пять строк, выполняется одна из демонстрационных программ, хранящихся в каталоге MATLAB7\ toolbox\matlab\demos (пример 4.9). Г Примерi 4.9. Запуск демонстрационной программы а ;г^'' ^---/^^¾¾½¾¾ function showdemo(demos) errstring = 'Файла с таким именем в каталоге нет"; п = input['Выберите номер демонстрационного файла: ') demos(n,:) eval(demos(n,:),'[errstring demos(n,:)]') Для запуска этой программы наберите в командном окне две следующие строки: >> D = [.'o'dedemo'; 'quademo'; ' fTitdeirio' J ; »■ showdemo(D) Первая из них содержит список имен m-файлов, два из которых действительно находятся в указанном каталоге (odedemo.m — демонстрация методов решения обыкновенных дифференциальных уравнений и fitdemo.m — приближение нелинейной функцией экспериментальных данных). После старта приложения вам предложат ввести одно из чисел I, 2 или 3 для выбора имени демонстрационного примера. На выбор п=2 последует сообщение о том, что файл с таким именем в каталоге не представлен. Функция f eval по логике своей работы отчасти напоминает функцию eval
146 Глава 4 Обычно ей передают указатель hFun на функцию, подлежащую выполнению, и список параметров, передаваемых косвенно вызываемой функции: [yl,y2,...] = feval(hFun,xl,х2,...); Второй формат вызова функции feval предполагает, что ее первым аргументом является строка с именем функции: [yl,y2,... . feval{'Name_fun'fxl,x2,...); Этот вариант считается устаревшим, но его сохранили для преемственности с ранее разработанными приложениями MATLAB. Следует заметить, что точными эквивалентами второго формата вызова являются и следующие обращения: [yl,у2,..Л = feval(@Name_fun,xl,х2,...}; fy'l, y2, . . . ] = Name_fun(xl, x2, . . .) ; Основное назначение функции feval — вычисление значения функции в теле процедуры, которой среди входных параметров передали указатель на функцию. 4.9. Специфика работы в редакторе m-файлов Редактор m-файлов вызывается по команде File | New | M-File (Файл | Создать | М-файл) или при одинарном щелчке на имени m-файла. Главное меню редактора несколько отличается от глапного меню MATLAB, да и панель инструментов здесь гораздо богаче (рис. 4.4). Cut Г Сору Paste Я Editor - Untitled Find text Top/Bottom Split г Show functions Left/Right Split Step In -i rStepOut Tile Hie Edit Jfait p! Tods Debud Ctsktop Window 4;lp Ые?|и I .», 4» №, '■ '■ ■"" #| «j fj К. jpj. -I? Ъ№ Р)вГ |a«t| ~Б gjJBljk?-JD TnR Save Open file New M-File L Print L- Redo Undo Run J L Exit Debug Mode L Step Float L Clear Breakpoints in All Files Set/clear breakpoint Maximize Рис. 4.4. Панель инструментов редактора m-файлов
Программирование вычислительных процессов 147 Большинство разделов главного меню в редакторе кода совпадает с аналогичными разделами главного меню среды MATLAB. Однако состав команд в соответствующих разделах поменялся, в основном в сторону увеличения количества команд. Так, например, в меню File (Файл) появились команды Publish То HTML (Экспортировать в HTML) и Publish То (Экспортировать). С их помощью программа, набранная в поле редактора, может быть экспортирована в документ, создаваемый в одном из форматов — HTML, XML, LaTeX, MS Word, MS PowerPoinl. Документ, экспортированный в формате HTML, сохраняет раскраску синтаксических единиц, действующую в редакторе кода. В окне редактора можно открыть несколько m-файлов и одновременно наблюдать тексты нескольких программ, разделив поле редактора на части (Tile), горизонтальные (Top/Bottom Split) или вертикальные (Left/Right Split) полоски, расположив панели с программами друг за другом (Float) или развернув одну из программ на все окно (Maximize). На рис. 4.5 приведен вариант горизонтального расслоения поля редактора после вызова программ array2vec.m и fcrn.m. Имена вызванных программ отображаются в строке Document Bar (Строка документа). Q) Editor File Edit Text Cell Tools Debug Desktop Window Help ^'^sPfS'^T^. .sax \-. ■ т-гг t - 1 function [varargout] = array2vec (a) 2 - foe k=l:narcfout 3- varargout[kl=a(k,:); 4 - end H:\MATLAB7 work\fern.m 1 , function fern 1 ■■ИГЕТ'.Ы M?.T!A& i^-Lou'.-n-ftliin of г",.;, fractal f-ssn 3 4 MichacL' P:ii n-r'lcy, Frartnlf Kvc:.ywl!'--£.-. Лта^сгс!'-- I't-i-: 4 5 Tils vtrir-iori L-j-JiH f nciv-.i, 01 Jl.NJl :---trT- 1« 1-X)t|lel 5 ? a-_« -jlsc-.: i'lfeii'ISh-t.Ki. 6 - shg 7 - elf reset 8 - set (act, 'coioi:', 'white-', 'iuoi-iub-ai:', 'вопс-', ... I array2vec in * .[ (em m * " |fem Kn 1" ЯПВ "x i ▲ zl * X ▲ ■=2 '• '1Ч'\ zl Col 1 \-tif v Рис. 4.5. Две m-программы в поле редактора кода Среди разделов главного меню появились новые разделы — Text (Текст), Cell (Ячейка) и Tools (Сервис).
148 Глава 4 4.9.1. Меню Text Меню Text (Текст) главным образом ориентировано на управление текстом программы иа поле редактора (рис. 4.6). Text Evaluate Selection Wrap Selected Comments Comment Uncomment Decrease Indent Increase Indent Smart Indent F9 Ctrl+R Ctrl+T Ctrl+t Ctrl+] Ctrl+I Рис. 4.6. Команды меню Text Команда Evaluate Selection (Вычисление выбранного) обеспечивает вычисление выделенного выражения, если в этот момент известны значения всех переменных, входящих в формулу. Результат вычислений отображается в Command Window (Окно команд). Команда Wrap Selected Comments (Переносить выбранные комментарии) имеет смысл только в том случае, когда отключен режим автоматического перехода на следующую строку при наборе длинных комментариев. В настройках Preferences | Editor/Debugger | Language (Предпочтения | Редактор/Отладчик | Язык) имеется возможность управлять форматом набираемой программы. Во-первых, это список языков программирования — М (MATLAB), C/C++, Java или HTML. Во-вторых, это подключение или отключение режима подсветки синтаксических конструкций (Enable syntax highlighting). В-третьих, это выбор режима отступа (Indenting for Enter key) для выделения вложенных конструкций. Наконец, это управление длиной строки комментария (Comment formatting) и его автоматическим продолжением со следующей строки при превышении установленной границы (Autowrap comments). Если режим автоматического переноса отключен, а комментарий набран без соблюдения установленного предела, то любой его фрагмент (хотя бы один символ) надо выделить. После выполнения команды Wrap Selected Comments (Переносить выбранные комментарии) длинные комментарии будут автоматически укорочены за счет переноса избыточных хвостов в начало следующих строк. Команда Comment (Комментировать) позволяет закомментировать текущую строку. Конечно, это можно сделать и вручную, установив символ % в первой позиции текущей строки. Превращение текущей строки в комментарий позволяет временно отключить некоторые операторы па время отладки оп-
Программирование вычислительных процессов 149 ределенных фрагментов программы. Команда Uncomment (Раскомментировать) возвращает закомментированный в текущей строке оператор в первоначальное состояние. Термин indent (отступ) означает автоматический отступ текущей строки по отношению к предыдущей строке. Вы, наверное, наблюдали, как после оператора for следующая строка автоматически сдвинулась вправо, наглядно представляя вложенность тела цикла. И все последующие строки тела цикла начинаются с этой же границы. Иногда полезно вмешаться в этот режим, например, чтобы очередной оператор end, завершающий тот или иной программный блок, оказался на уровне заголовка блока. И тут на помощь приходят команды Decrease Indent (Уменьшить отступ), Increase Indent (Увеличить отступ) и Smart Indent (Интеллектуальный отступ). Первая из них смещает текущую строку или выделенный блок строк влево на установленное число позиций (величина этого смещения регулируется в окне Preferences (Предпочтения)). Вторая команда осуществляет аналогичный сдвиг текущей строки или выделенного блока строк вправо. Команда Smart Indent (Интеллектуальный отступ) реализует интеллектуальный отступ — например, выравнивает на общую границу пару for.. .end или подравнивает все внутренние команды блока, если они по какой-то причине начинаются с разных позиций. 4.9.2. Меню Debug Меню Debug (Отладка) включает команды, управляющие режимами отладки (рис. 4.7). Debug | * Open M-Flles when Drugging Step ' ■ F10 Step In Fli Step Out Shlft+Fll Ru-i F5 Go Lhtil Cursor _____ __ . Set/Clear Breakpoint F12 Set/Modify Conditional Breakpoint... EnableyDlsable Breakpoint _ ■■ Clear Breakpoints in All Files .■ "'*" " Stop If Errors/Warnings,,. .'■ Exit Debug Mode Рис. 4.7. Команды меню Debug
150 Глава 4 Команда Run (Запуск) или нажатие клавиши <F5> инициируют автоматическое исполнение программы. Команда Step (Шаг) включает режим пошагового выполнения m-файла — при каждом нажатии клавиши <F10> система интерпретирует очередную исполняемую строку программы. Режим Step In (Шаг внутрь) устанавливает точки останова на первых исполняемых строках каждой подфункции. Это позволяет проконтролировать в отладочном режиме выполнение тех или иных операторов внутри подфункций. Режим Step Out (Шаг наружу) исключает подфункции из отладочного режима, предоставляя им возможность выполняться автоматически. Во время выполнения программы команда Run (Запуск) подменяется командой Continue (Продолжить), которая после останова программы вновь переводит ее в режим автоматического исполнения. Термин breakpoint (точка прерывания) обозначает строку программы, на которой компьютер должен приостановить режим автоматического выполнения, предоставив пользователю возможность произвести некоторые отладочные действия. Самый простой способ выделения строки в качестве точки останова — щелчок по знаку "минус", расположенному справа от номера строки. Строки, отмеченные как точки прерывания, выделяются красными маркерами между колонкой номеров строк и первой позиции. Если вы пытаетесь объявить какую-либо исполняемую строку точкой останова, и вместо крас- "ного маркера появляется серый, то это означает, что программа в поле редактора подверглась модификации и еще не была сохранена. После запоминания ее текста в дисковом файле серые точки останова становятся красными. Команда Set/Clear Breakpoint (Установить/Убрать точки прерывания) выделяет текущую строку как точку останова или отменяет ранее сделанное выделение. Команда Set/Modify Conditional Breakpoint (Установить/Изменить условие точки прерывания) открывает диалоговое окно (рис. 4.8), в котором можно задать дополнительное условие. Если оно будет выполнено, то произойдет останов на заданной строке программы (точки условного останова появились только в MATLAB 7). В противном случае точка останова будет проигнорирована. Команда Enable/Disable Breakpoint (Восстановить/Отключигь гочку прерывания) позволяет восстановить или временно отключить точку останова. В последнем случае красный маркер перечеркивается крестиком, но не удаляется из программы. Повторное выполнение команды отменяет предыдущее действие. Команда Clear Breakpoints in All Files (Удалить точки прерывания из всех файлов) отменяет все выделения во всех одновременно открытых файлах.
Программирование вычислительных процессов 151 Q MATLAB Editor File H-VilATLAB7VworkAarray2vec.m Cortcftion for lire 4 (for example,x = ЛУ. □ Note: Itie condition win be checked before tne line is executed. OK Cancel Help Рис. 4.8. Окно для набора условия в точке останова Команда Stop if Error/Warnings (Остановить при ошибке/сообщении) открывает диалоговое окно (рис. 4.9), в котором имеется 4 вкладки — Errors (Ошибки), Try/Catch Errors (Ошибки iry/catch), Warnings (Сообщения), Nan or Inf (Nan или In!7). На каждой из них можно установить один из режимов: □ Always stop if warning (dbstop if warning) — всегда останавливаться в соответствующей ситуации; П Never stop if warning (dbstop if warning) — никогда не останавливаться в соответствующей ситуации. Кроме того, системное сообщение о произошедшем событии можно заменить пользовательским сообщением. f| Stop if Errors/Warnin... Errors | Tiy/caich Errors Warnings | f)an oc inf | f Never stop H warning CdbckKir if warning) f* Always etop tf warring (dbstop H warning) F* use itttssage Identifiers (dbstop IT wamirc messaged) МуТогЛах FlleNotFouldError |L .Adj.. OK Cancel Help Add Message Identifier П Identifier: Myl oolbov: FteHotFcunciEricir Example: MyToolbOJcFfleNotFtwritfci-rar OK Cancel J l-lelp | Рис 4.9. Изменение условий останова при ошибках или предупреждениях Команда Go Until Cursor (Продолжать ло текущей строки) добавляет к точкам останова текущую строку. Прерывание программы в случае выхода на точку останова или в результате возникновения запланированного события переводит MATLAB в режим отладки. Отличительным признаком этого режима является изменение под- 6 Зак. SW
152 Глава 4 сказки в командной строке — вместо символов » появляется тройка к». В качестве рабочего пространства теперь выступает локальное рабочее пространство отлаживаемой функции, и пользователю доступны все команды MATLAB. С их помощью он может проанализировать значения тех или иных переменных, вычислить нужные выражения, предпринять другие отладочные действия. Команда Continue (Продолжить) продолжает работу приостановленной программы. Выход из режима отладки обеспечивает команда Exit Debug Mode (Выйти из режима отладки). Первые 10 кнопок на панели инструментов редактора дублируют наиболее часто используемые команды меню File (Файл) и Edit (Правка). Смысл большинства кнопок в правой части панели инструментов становится ясным после знакомства с командами назначения точек останова и управления режимами отладки. Кнопка Show function (Показать функцию) позволяет быстро перейти к тексту нужной подфункции. Щелчок по этой кнопке выдает окно со списком всех подфункций данного m-файла (рис. 4.10). Последующий щелчок по имени нужной подфункции переводит курсор в начало выбранной функции. 31 Editor - C:\MATLAB6p5\work.l\calll.ni File Edit Text Cell Tools Debug Desktep Window Help _ D c£ Й ! ,*■ "fa &, " " | "<S ' "** jJ~Q & i ^ '^ ^т >Ш Ш i.a«dr|iw~l| 1 z 3 4 5 6 7 function varacgout = < ■\ CALLl И-fil-a fi-.i ceJ Г£]".:.^, by ::?.eJ U = .-.i'.L.i :.-:;!:h: 2 the -"tiir 1 r.-J '-■ calll calllJDpeningFcn call iJXitputftn f'igurel_ButtonDownFcn pushbutton2_Callback r-tii---,-n'-. . ,_L ОГ raiSia:? ■■•■• CST.L1 c-r "h^ -rXiStili'J th( lia.ndJe '-.w Рис. 4.10. Список подфункций файла calH.m 4.9.3. Меню Edit Быстрые перемещения по программе в поле редактора дополнительно обеспечиваются командой перехода на строку с заданным номером и использованием закладок (bookmarks). Эти средства сосредоточены в разделе Edit (Правка) главного меню редактора (рис. 4.И). Выполнение команды Go То Line (Перейти к строке) приводит к появлению диалогового окна (рис. 4.1.2), в котором следует набрать номер искомой строки.
Программирование вычислительных процессов 153 Edit . Undo Redo Cut Copy Paste' Paste. Special,-.., ■Select All Delete Find end Replace... Find Next Find Previous Find Selection Find Files... Go To Line .Set/Clear Bookmark Next Bookmark- Prev Bookmark ■ Clear Command Window Clear Command History Clear Workspace Cfrl+Z Ctrl+Y Cirl+X "" Ctrl+C Ctrl+V Ctrl+A Delete Ctrl+F F3 Shlft+F3 CM+F3 Ctrl+G Ctrl+F2 F2 =SJ1ft+F2 Рис. 4.11. Меню Edit Go To Line Line number: Щ П OK Cancel Рис. 4.12. Диалоговое окно перехода на строку с указанным номером Bookmarks (закладки) могут быть присвоены наиболее посещаемым строкам профаммы с помощью команды Set/Clear Bookmark (Установить/Удалить закладку). Слева от такой строки появляется голубенький прямоугольник (рис. 4.13). Повторное выполнение, этой же команды, когда курсор находится в помеченной строке, удаляет закладку. Естественно, что применение закладок имеет смысл только в длинных программах, текст которых полностью не отображается на экране. Переход к ближайшей закладке, расположенной ниже текущей строки, выполняется с помощью команды Next Bookmark (Следующая закладка). Воз-
154 Глава 4 врат на ближайшую закладку, расположенную выше текущей строки, осуществляет команда Prcv Bookmark (Предыдущая закладка). 'ДEditor - H:\MATLAB7\work\array2vec.m File Edit Text Cell Tools Debug Desktop Window Help D-eg а]'Ль as,~-■'^ \'m\h /.Га~ ё зйш 1вЖ|^[^1Г 1 function [vacargoutl =* acray2vec (a) 2- for: k»l:nargout 3-D vacargoutl k|=a (k, :) ; 4 - end Рис. 4.13. Закладка возле третьей строки Работа в любом текстовом редакторе, как правило, предполагает активное использование так называемых горячих клавиш. Редактор m-файлов располагает довольно скромным набором таких операций, их перечень приведен в табл. 4.2. Таблица 4.2 Клавиша/комбинация Операция клавиш <Т> Переход на предыдущую строку <1> Переход на следующую строку «—> Возврат на один символ <—» Переход на один символ вправо <Ctrl>+<—»> Переход на одно слово вправо <Ctrl;>+«— > Возврат на одно слово влево <Ноте> Возврат в начало строки <End> Переход в конец строки <Delete> Удаление символа над курсором <Backspace> Удаление символа слева от курсора <Shift>+<Home> Выделение текста от начала строки до курсора <Shift>+<End> Выделение текста от курсора до конца строки <Ctrl>+<Home> Перемещение в начало файла <Ctrl>+<End> Перемещение в конец файла
Программирование вычислительных процессов 155 4.10. Отладочные команды Команды меню Debug (Отладка), обеспечивающие работу с точками прерывания, и кнопки панели инструментов редактора, дублирующие некоторые из этих команд, являются не единственным набором отладочных средств. Кроме них MATLAB предоставляет в распоряжение пользователя группу команд (функций), к которым можно обращаться из командной строки (табл. 4.3). Таблица 4.3 Команда Назначение dbclear Очистка указанных или всех точек и условий останова dbcont Продолжение выполнения программы после останова ribdown Переход на рабочее пространство следующего уровня ' dbquit Выход из режима отладки ribstack Опрос состояния стека вложенных вызовов функций d-bs tatus Опрос установленных точек и условий останова dbstep Задание количества строк, выполняемых на очередном шаге dbstop Задание точек или условий останова dbtype Вывод m-файла или его фрагмента с номерами строк dbup Переход на рабочее пространство предыдущего уровня С помошыо функции dbtype можно вывести в командном окне текст пт- файла с номерами строк или фрагмент этого файла: » dbtype array2vec 1 function [varargout] = array2vec(a) 2 for k-1:nargout 3 varargout{k)=a(k,:); 4 end » dbtype array2vec 2:3 ,2 for k=l: nargout 3 varargout{k)=a(k, :) ; Такой текст позволит вам выбрать строки программы, которые целесообразно назначить точками останова. В командном окне для этой цели можно
156 Глава 4 воспользоваться функцией dbstop, обращение к которой допускает несколько модификаций: >> dbstop in array2vec at 3 % останов в файле array2vec.ra на строке с номером 3 » dbstop in array2vec % останов на первой выполняемой строке в файле array2vec.n! » dbstop in funl at subfun2 % Останов на первой выполняемой строке подфункции subfun2 % в файле funl.т » dbstop if error % переход в режим отладки, еслк Будет обнаружена ошибка »■ dbstop if warning % переход s режим отладки, если будет выдано предупреждение » dbstop if naninf » dbstop if infnan % переход в режим отладки, если обнаружено НаН или °° Служебные слова-связки типа if, in, at не являются обязательными и могут быть опущены. Для набора точек условного останова три первые модификации допускают расширение типа "if выражение". Останов происходит в том случае, если при выполнении указанного оператора значение выражения оказывается истинным. Вообще говоря, количество вариантов останова по dbstop достигает 17, и с их полным перечнем можно познакомиться, набрав В окне команд строку help dbstop ИЛИ doc dbstop. Обращаясь к функции dbstatus, вы можете получить список всех точек останова, действующих в данный момент (рис. 4.14). Для отмены конкретной точки останова или всех точек останова можно воспользоваться услугами функции dbclear: » dbclear in array2vec at 3 % отмена точки останова в строке 3 файла array2vec.m » dbclear all in arrayZ-vec % отмена всех точек останова в файле array2vec.m
Программирование вычислительных процессов 157 » dbclear all % отмена всех установленных точек останова » dbclear if error » dbclear if warning » dbclear if naninf % отмена заданных условий останова f| Editor - C:\MATIAB6p5\work\array2vec.m File Edit Text Ceil Tools Debug Desktop Window Help DcS &\ x fee •--.»'!#;« f.:flfi,««S JBfJ|si«cK|i-.u!E J ИПП » j и 'x 1швэ|п 1 function [varargout] = array2vec(a) 2* foe k=l:nargout 3<> veeacgout|k|=a(k, :) ; 4 - end <->MATLAB File Edit Debug ■ Desktop Window Help НПО D G? J Щ Щ Щ *~i Г* j Щ Ы" | ~?S | CurrertDlrectOTt-|c:ViW7LASEp5\work zj jj Ё] ' » dbstop etcay^wec 2 » dbstop cH'i-'dy^vec 3 » dbstatus Breakpoints for arrayZvec are on lines 2, 3. » Рис. 4.14. Установка точек останова и опрос статуса Останов по любому поводу (попадание в точку останова, выполнение одного из заданных условий) переводит программу в режим отладки, о чем свидетельствует появление буквы к перед символами ». В этот момент в командном окне действует локальное рабочее пространство функции — инициатора останова. Для пошагового выполнения программы в режиме отладки можно воспользоваться клавишей <FlO> (эквивалент команды Debug [ Step (Отладка | Шаг)) или функцией dbstep. Нажатие клавиши <FlO> или вызов функции dbstep без параметров приводят к выполнению следующей строки программы. Числовой параметр в функции dbstep обеспечивает выполнение указанного количества строк на очередном шаге отладки: » dbstep .5 Если в точке останова находится оператор вызова функции, то возможны два варианта — воспользоваться командой Debug [ Step In (Отладка | Шаг внутрь) (эквивалент— клавиша <F11>) или командой Debug [ Step Out (Отладка | Шаг наружу) (эквивалент — комбинация клавиш <Shift>+<Fll>).
158 Глава 4 В первом случае пошаговый режим выполнения программы распространяется на операторы вызываемой функции. Во втором случае вызываемая функция выполняется в автоматическом режиме, а после возврата из нее восстанавливается режим пошаговой отладки. После выхода программы на очередную точку останова вы можете просмотреть переменные локального рабочего пространства в окне, раскрывающемся по команде View | Workspace (Вид | Рабочее пространство) или при выполнении команды whes. Если имела место пепочка вызовов, то кроме текущего локального пространства могут представить интерес и переменные, принадлежащие предшествовавшим функциям. Перемещения по локальным рабочим пространствам вперед или назад обеспечиваются командами аьир (возврат в рабочее пространство предыдущего уровня) и dbdown (переход в рабочее пространство следующего уровня). Цепочку предшествовавших вызовов можно проследить по содержимому стека обращений. Оно отображается по команде dbstack. Находясь в отладочном режиме, можно не только просматривать текущие переменные, но и менять их значения, а также выполнять любые команды, которые разрешается набирать в командном окне. С помощью функции dbquit осуществляется выход из отладочного режима. Ее эквивалентом в главном меню является команда Debug | Exit Debug Mode (Отладка | Выйти из режима отладки). К режиму проверки корректности программы относится ее проверка с помощью сервисной программы M-Linl, которая вызывается по команде Tools | Check Code with M-Lint (Сервис | Проверить код с помощью M-Lint). Идея полного синтаксического контроля программы и выявления в ней подозрительных мест принадлежит сотрудникам BELL Laboratories. Она была реализована примерно 30 лет тому назад в виде утилиты lint, через которую пропускались все программы, написанные на языке С. В профамме lint проверялись такие ситуации, как неправильное использование типов, ошибки в передаче параметров функциям, неиспользуемые и неинициализируемые переменные и многое другое. В том числе она выдавала сообщения о трудностях переноса программы на компьютеры другого типа, связанные с разрядностью, количеством регистровых переменных, порядком следования байтов, размножением знака при сдвиге чисел вправо и т. п. Если программа проходила такой контроль, то она компилировалась с помощью достаточно простого компилятора, не предусматривающего столь тщательные проверки. Своим названием программа lint предположительно обязана аббревиатуре от Language Inlerprcier (интерпретатор языка). Попытка реализации аналогичной идеи была предпринята в MAT LAB 7. Возможно, что работа нал сервисом подобного рода будет продолжена, т. к. некоторые наши попытки внести ошибки в достаточно простую программу ставили M-Lint в тупик. На рис. 4.15 приведен результат анализа функции polyline, не содержащей ошибок.
Программирование вычислительных процессов 159 Э Editor - H:\MATLAB7\work\polyline.m File Edit Text Cell Tools De^jg Desktop Window Help ■_ DSB1 *■ «h Ш «' «•» ; ¥ I 44' /.-■' e €1 i :Ш *i © ЛЭШ ''stadc|e».^j 1 |function polyline(varargin) 2- for k=l: length (varargin) 3- x(k)=vara.rgin(k) (1) ; "4- y(k)=vacaL'gin(k) (2) ; 5- end 6 - axis ( [min (x) max (x) min(y) max (y) ]) 7- plot(x,y) fV'M-Lint Code Check Report File 'Edit View Go Debug Desktop Window Help __„____ njx Refresh J M-Lint Code Checker Report Report for file H: \MATEAB4-\waEk\polyline j H:\HATbAB7\trjork\polyline.m messages ; 3^_ Acray 'x' is constructed using subscripting. Consider ^reallocating for speed 4:_ Array Ty" is constructed using subscripting. Consider ^reallocating for speed Рис. 4.15. Сообщения синтаксического анализатора M-Lint %VM-Lint Code Check Report File Edit View Go Debug Desktop Window Help M-Lint Code Checker Report Report tor tile i\: \riA'l'IiAB"?\molj~\plj!yli H:\MATIiAB7\work\polyline.m 4 messages 1: Invalid character 1: Function name 'olyline' will bo known to MA'CLAB by its file паше: 'polyline'. '3.: Array 'x" is constructed using subscripting. Consider praallocatino, for speed 4: Array 'y' is constructed using subscripting. Consider ^reallocating for spepd Рис. 4.16. Пример хорошей реакции на ошибку в программе
160 Глава 4 Несмотря на это, M-Lint выдала сообщения о том, что в 3-й и 4-й строках программы использованы индексированные массивы и не мешало бы подумать над способами повышения скорости работы программы. Над попытками включить в программу неинициализированные переменные анализатор M-Lint надолго задумывался, но никаких сообщений не выдавал. Зато на использование запрещенного имени функции (вместо polyline мы набрали noiyiine) выдал очень разумное сообщение (рис. 4.16). 4.11. Анализ эффективности программы MATLAB 7 отличается от предыдущих версий еще и тем, что в его состав входит утилита Profiler, которая позволяет построить профиль программы, т. е. получить статистику по времени ее выполнения вплоть до каждой строки исходного кода. Это помогает определить узкие места программы, выделить строки программы, которые никогда не выполняются, узнать количество обращений к той или иной функции и время ее работы. Вызов программы Profiler может производиться разными способами: из среды MATLAB (команда Desktop | Profiler (Рабочий стол [ Профайлер)), из редактора кода (команда Tools | Open Profiler (Сервис | Открыть профайлер)), из окна Command Window (Окно команд) с помощью строки profile viewer. В окне Profiler (Профайлер) в поле раскрывающегося списка Run this code (Запустить код) набирается имя анализируемой программы (рис. 4.17) и нажимается кнопка Start Profiling (Создание профиля). Как видно из приведенных ниже рисунков, анализировалась программа bench.т, которая используется для определения производительности компьютера и сравнения ее с лучшими моделями ПК. Рисунок 4.17 отражает первичную выдачу результатов анализа, которая начинается со списка выполнявшихся функций. В колонке Function name (Имя функции) указывается имя функции, в колонке Calls (Вызовы) — количество ее вызовов, в колонке Total Time (Всего времени) — общее время пребывания в теле этой функции, включая и время работы всех вызываемых ею функций, в колонке Self Time (Собственное время) — исключено время работы вызываемых функций, а в последней колонке графически отображены оба указанных времени, выделенные разными цветами. Порядок функций в списке соответствует последовательности их вызовов. Если щелкнуть мышью но заголовку Function name (Имя функции), то список перестраивается в алфавитном порядке, что упрощает поиск нужной функции (рис. 4.18). Щелчок по имени функции перемещает нас на соответствующий кадр отчета (рис. 4.19). В нашем примере была выбрана функция ode45.m.
Программирование вычислительных процессов 161 Profiler ♦•чей \'& | « StwiPiolfevjl fcj\WscCKh£| bench Г " ~~ "" Profile Summary ! Generated U-Sep-2004 18:54:26 Function name 1 bench ode45 newplol iiewpIot>ObserveAxes>.rextPlot grapIiicsVprivaleXcIo 1 b_nu|i membrane 1 rcpmal iiiiifun\priv!iieVntrp4S Proite 1 Commend V.1«Jow I <kSlul| i Calls J- ;1 \l 47 1 47 47 2 ■ 4. 2166 , 1080 Total 1 6.797 s 0.984 s 0.422 s 0.391 s 0.359 s 0.219 s 0.203 s 0.203 s 0.188 s Self Time* 4.703 s 0.547 s 0.031 s 0.000 s 0.156 s 0.000 в 0.063 s 0.203 s 0.031 s r zl:«> >то№11те:Л08ёе Total Time Plot (dark band = self time) шш^шяш ■3 « it '■ 1 ' ■ 1 i i i i i i 1 . l J /> Рис. 4.17. Начальный кадр отчета программы Profiler Profiler +• <+-С tUIS'M sort Prolyl Run Ws code | bench Profile Summary Generated ll-Sep-2004 21:06:32 ■ Function name ■ ancestor ancestorHsalvpe autoinc-sh axes (Opaque-function) 1 axesclieck ; Hsis nxis^LocSetLiniits _ Calls 60 120 7 80 5 3 1 Total Time. 0.063 s 0.031 s 0s 0s 0.016 s 0.031 s 0.016 s » X ^J ^ProlirilliM-IOjec Self Total Time Plot Time* (dark band = self time) function is recursive function is recursive 0.000 s 0.000 s 0.016 s 1 ' 0.016 s | 0.016 s ; Рис. 4.18. Профиль программы с упорядоченным по алфавиту списком функций
162 Глава 4 Profiler Sail Pnfflre] feJnlhlEccde: Iberch •*| ♦.ProIllelmeilOKC ode45 (2 calls, 0.984 sec)' Generated Il-Sep-2004 21:09:54 M-function in file H:\MATLAB 7'Joolbpx'-iiialliJ>\runliintode45.m [£.°1&!!° .u£w wjudow lor comparing нш1пр1с..шш?] Reftosn | P Show parent files P Show busy lines P Show child files P Show M-Lini results <* Show file coverage P Show file listing Parents (calling fund ions) Filename File Type Calls bench M-funclion 2 Lines where the most time mis spent Line Number Code Calls Total Time % Time Time Plot Protihlr]Cc<fflrflndv»dtiw| j^StenJ 'il Рис. 4.19. Начало профиля по функции ode45.m Profiler 4- ■*• О А «3 *4 Нв1РтоП1пд[ RwltNscooc: ] bench Lilies whore the most time was spent Line Number ■ffl Ш. -У.5 325 Й1 Otlier lines & overhead Tolals Code youI:_riavi = luTirpfl; (tcef, t, у, [I . . t(:,4) = fevnWocSeFcn. T^liAP), . . f(j,3] = 1 eve 1 (sdr-F^n. r-hA [2)-. .. ft:,2) = ipvoHMaFcn. t*h_M.U , .. Children (called /unctions) «1 Prolllsr 1 Ccimrnr.dVAWov.' | ^vsiirtj Calls ■ 1080 ■ 1326 t ■ 1326 • 1326 Total Time 0.23.1 s 0.094 s 0.063 s 0.063 s 0.063 ? 0.469 s 0;9K4 £ _ d % Time 23.8%. 9.5% 6.3% 6.3% 6:3% 47.6% 100% 1 ¥ X ♦ Prof lo urn, 10 sec _J Time Plot — ■ ■ о ■ — 3 s Рис. 4.20. Статистика по работе функции ode45.m
Программирование вычислительных процессов 163 В этом фрагменте профиля можно увидеть (рис. 4.20) статистику по наиболее долго выполнявшимся строкам программы. Следующий кадр (рис. 4.21) отражает статистику работы вызываемых функций. ♦••*:--. ^а а л 53nrt Prefbnp | RltIWs code: ] bench Children (called functions) Filename &»funiprivaicaihTj45 V(Ip 1 furiftn'jirivaKAocIear^uincirts ftuiiuiityrivnic lode-final ize limfiimprivateVodemass odegel ftuifimtynvoreXoflecvents Self time (buill-iiis. overhead, Totals i FrolHer [ccmmendWndow j ф Start | File Type M-fuiicti'on M-fiuicliou M-funclion M-fimction M-fuiiclion Ivl-fuiiciioil M-fiiuction etc.) Calls 1080 7956 2 2 2 6 2 Tola! Time 0.188 s 0.109 s 0.063 s 0.063 s 0.016 s 0s Cs 0.547 s 0.984 s % Time 19.0% 11.1% 6.3% 6.3% 1.6% 0% 0% 55.6% 100% J*J ^ Pi'oil* tune Time Plot - a f i i _J 10 з« j Й Рис. 4.21. Статистика по работе функций, вызываемых из ode45.m Предпоследний фрагмент отчета (рис. 4.22) включает предупреждения программы M-Lint и итоговые результаты профилирования. Самая последняя часть отчета содержит текст анализируемой программы с указанием времени работы каждой строки. Не выделенные цветом строки — затратившие меньше всего времени, слева от их текста ничего не указано. Затем по мере возрастания времени работы окраска строк изменяется от светло-розовой до темно-красной (рис. 4.23). Полученный профиль можно сохранить в файле для последующего изучения узких мест программы с целью повышения ее производительности.
164 Глава 4 Profiler «• •* о л. & ;■** SJ*1Pro№rig[ Run W» coda, jbtnch . ftl-Luit results Line number Message 402 ^be value aaaignod hexre to variable 'ignore* Coverage results \ Show coverage for parent directory 1 Total lines in file 513 ' Non-code lines (comments, blauk lines) 199 Code lines (lines that can run) 283 Code lines that did ran 155 Code I ines that did not run 128 Coverage (did run/can run) 54.77 % ■■«1 Profile* ]-CwnmenflVvVH)ow | ^St»rt| л X **] фРгоПскпеЮвое "" " " ' ' "4 i ia nisvBE uaecl | ' 1 1 1 1 1 i i 3 Рис. 4.22. Итоговые результаты профилирования Profil 4- ■* a Start Proimg ,!i-. . US 1 1 1 1 l ■ 11 1 ■ JS m ."". j:'.- <l er й!<9|« №iim«i№|b«Kh mso 32o ioso _37i 1Э7.6 322 13S5 эгз U2u _32J И* -MS 1эгб _Э26 иге я?7 1Л2Й _Э2И 1.326 ЗЭО i3ze эзз ■s _MZ 5 _33J ж* _ш 1зг«, ззц 1эгй _эз*. Praliter I CowAfld window] Фявп[ < "1." "Г S" -1 nofailed = while true hA = h • ЬВ = h - £(:,2) = t(:,2) = £(:,4) = «(=.5) = £(:,6) = t.new = t i£ clone tnew = end h = .fcne'-n ynw = у £(:,7) - Г d true; Й no faij-ed a-fceem ф Prnffleffre: 10 A; B> teval (odcFcn, t+hA(l) , y+£*hB (.,1), odeArga [ : }) t eval (odeFen, t+hA(2) , y+fhE (:,2), odeArg-sJ : 1 ) fevalfodeFen, t+hA£3 ), У» **"№£: ,3). odeAtKal: )1 fevelCedeFcn, t-i-hAH) ,y+f *hB(: , 4 } , odnAegsJ ; \ ) fevuliDdeFcn, t+hA.£5),y+f *hB(: ,5), adeArnsf : () + hA£S); tiinal; ft Hie end point exactly. - tj i Purify h. *■ £.'hB(:,6j; fevol fodeFcn, tnew, ynew, odcAraaI:">) ; 1 X вес ; 1 ! 1 1 1, i "j A 4 Рис. 4.23. Текст исходной программы с информацией о работе каждой строки
Глава 5 Обработка символьных данных 5.1. Создание символьных объектов Чаше всего в системе MATLAB приходится работать с символьными данными в виде строк (векторов-строк размерности 1х/и), массивов строк равной длины (матриц размерности пхт) и массивов ячеек, каждая из которых представлена строками разной длины. Создание соответствующих переменных происходит при формировании тех или иных символьных значений с помощью оператора присваивания (пример 5.1). [: Пример "Й#:уЗри^^ % Формирование вектора-строки >> str='ABCDE' str = ABCDE » whos Name Size Bytes Class str 1x5 10 char array Grand total is 5 elements using 10 bytes %■ Формирование массива строк » st.r_mas=['1234'; 'ABCD'] strjmas = 1234 ABCD » whos Name Size Bytes Class str_mas 2x4 16 char array Grand cotal is 8 elements using 16 bytes % Формирование массива символьных ячеек » str cell=[{'123',,ABCD');{,4567,f*abc'}]
166 Глава 5 str cell = 423' '4567■ » vjhos Name str .cell '7ABCD' ■abc' Size 2x2 Bytes Class 263 cell array Grand total is 18 elements using 268 bytes На каждый символ во внутреннем представлении отводится по 2 байта в кодировке ASCII Unicode. Однако для программистов, привыкших к однобайтовой кодировке ASCII (в Windows — кодовая страница 1251), никаких вопросов с числовыми кодами букв латинского алфавита не возникает: char(65)=A char{66)=3 ... char(90)=Z int8('A'|=65 LntB('B'}='66 ... int8('ZM=90 char(97)=a char(9-8)=b ... chart 122 )=z int8('.a')=57 intS('b')=9S ... intS t 'г' )=122 Для преобразования символа в числовой код можно воспользоваться любым ДОПУСТИМЫМ форматом — uintS, intib, uintlE, int32, uint32, single. double. Однако с типами inte или uinte вас могут поджидать неожиданности, т. к. в этом преобразовании участвуют только 7 или S младших битов. Если преобразуемый код выходит за пределы допустимого интервата, то результат заменяется соответствующим граничным значением: int8('fl')=127 uinc8(,R,)=255 Дело в том, что для символов русского алфавита используется настоящая двухбайтовая кодировка: chart 1040) =А char (1041)=Б ... char. (10.71 )=Я char(1025)-E апсШ'А'НЮЗ intl6('B*)=10'1 ... intl6('Я')=107 intl6 ('Е')=1025 0 1 1 char(1072)=a char(10/3)=6 ... спаг(1103)=я char(1105)=е intl6('a')=107 intl6('6')=107 ... intl6('я')=110 intl6('e')=1105 2 3 3 Аргументом функции char может быть не только целое положительное значение в формате double, но и любой числовой массив с такими же компонентами: » char([48 49 50; 65 66 67; 1088 1089 1090]) ans = 012 ABC рст
Обработка символьных данных 167 С помощью индексной конструкции типа сокращенного цикла (п1.-л2) и функции ehar можно сформировать строки, представляющие наиболее употребительные фрагменты таблицы ASCII (пример 5.2). \ Пример 5.2* Печать таблицы ASCI! ^^4Ш0^&^'-:^^^^^Ф^ -.-:$■ i » char(32:64} ans = !"#$%&' ()*+,-./0123456789:;<=>?@ » char(65:96) ans = ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]Л_" » char(97:126) ans = abcdefghijklmnopqrstuvwxyztI}~ » char(1025 1105) ans = Ее » char(1040:1071) ans = АБВГДЕЖЗИЙКЛШОПРСТУФХЦЧЖЦЬЫЪЗЮЯ » char(1072:1103) ans = абвгдежзийк.пмнопрстуфхцчшщъыьэюя Если в качестве аргументов функции char выступают строки разной длины, то функция возвращает символьный массив, дополняя более короткие аргументы пробелами справа: » char('ABC, 4234') ans = ABC 1234 Наконец, аргументом функции char может быть массив ячеек, каждая из которых, в свою очередь, представлена строкой. И в этом случае функция char в качестве результата тоже возвращает символьный массив, размещая в каждой его строке очередную ячейку и выравнивая длины строк (пример 5.3).
168 Глава 5 |Пример 5.3. Преобразование массива ячеек в символьный массив. ^\^$^ШЦ 1 » S=char(f 'ABC, 4234*}) S = ABC 1234 » whos Name Size Bytes Class S 2x4 16 char array Grand total is 8 elements using 16 bytes Таким образом, с помощью функции char допустимо формировать символьные строки или массивы строк. И в качестве ее аргументов могут выступать не только отдельные строки, но и символьные массивы. Для доступа к любому фрагменту строки можно использовать пару индексов, разделенных двоеточием (пример 5.4). г Пример 5.4. Выделение фрагментов строки ^'^^4™:^!:#^1'|^:^й?'^>йж-Т Т Л » S='C Новым Годом!'; » S(l:2) ans = С » S(3:8) ans = Новым » S(9:end) ans = Годом! Служебное слово end заменяет максимальное значение индекса. Из массива строк с помощью двух индексов i и j (i — номер строки, j — номер столбца) можно извлечь любой символ (пример 5.5). I Пример 5.5. Извлечение символа из массива строк Ci-,f-a -л-':' ко *--м-4 ■ ■"■^i » s=char([48 49 50; 65 66 67; 1088 1089 1090]) 012
Обработка символьных данных 169 ABC рст » s(2,3) ans = С Для того чтобы извлечь из массива строк нужную строку, можно воспользоваться одной из индексных конструкций, представленных в примере 5.6. » s (2,:) ans = ABC » s (2,l:end) ans = ABC Из массива ячеек с помощью индексных выражений можно извлечь конкретную ячейку, строку или столбец ячеек (пример 5.7). ; Примеру fcf/';'Vl-«-?^,,^/>"Tj£:jv'"1k" v "" . -j » s_c=H423', 'ABCD');{'4567', 'abc'l] s_c = '123' 'ABCD' •4567' 'abc' » s_c(l,2) ans = ■ABCD' » s_c(l:2) ans = • 123' •4567• » s_c(l,:) ans — '123' '.ABCD' Особую роль в символьных данных играют пробелы, обычно выступающие в качестве разделителей слов. Иногда их приписывают в начало или в конец строки для того, чтобы произвести соответствующее выравнивание по левой границе или по длине. Для формирования строки, содержащей заданное
170 Глава 5 количество пробелов, можно воспользоваться функцией blanks (п). Лидирующие и концевые пробелы можно удалить с помощью функции debiank. Если в строке присутствуют начальные и конечные пробелы, то, не изменяя длину строки, с помошью функции strjusu можно ее значимое содержимое разместить строго по центру, прижать к левой или правой границе (пример 5.8). Т- : '"""ШШ У Пример 5.8: Выравнивание строки< » 5=' 12345 S = 12345 » SL=strjuat(S,'left') SL = 12345 » SC=strjusc(S,'center'J SQ = 12345 » SR=Ftrjust(S,'right') SR = 12345 » SRl=strjust(S) SRI = 12345 >> whoe Name Size S lxll SC lxll SL lxll SR lxll SRI lxll * - Iм5,1 .,■ Bytes 22 22 22 22 22 з®,Ш- Class char array char array char array char array char array Grand total is 55 elements using 110 bytes В отличие от языка С, строки MATLAB не завершаются нулевым байтом. Это означает, что набор символьных данных класса char хранит длину текущего значения строки, которое может быть опрошено с помощью функции length: » length{'ABC') ans = 3
Обработка символьных данных 171 Применение функции length к символьному массиву позволяет определить длину любой его строки: » S=['ABC '; 4234'] S = ABC 123.4 » length(S) ans = 4 MATLAB позволяет работать со строками практически неограниченной длины. Строку или массив строк, заполненные одним и тем же символом, можно создать с помощью функции repmat (размножение матрицы) — пример 5.9. ;■■ ■■"■■"•••• v-'-'i";""--?--^^^ г Пример 5Д, Запо^нщ^ро^01^Щ^Ш^Ш^-' *f^M$?V^# >",* ,, г! » repmat {' = ', 1,4} ans = » repmat С*', 3,4) ans = ■*■*-* + А--* А* 5.2. Конкатенация строк В простейшем случае результатом конкатенации двух строк si и S2 является строка, получаемая приписыванием значения S2 вслед за значением si. Такая процедура носит название горизонтальной конкатенации и выполняется с помощью функции strcat: S = strcat(SI, S2, S3, ...) Если аргументами функции strcat являются строки, то она возвращает строку, полученную в результате последовательного присоединения значений входных операндов друг за другом (пример 5.10). I Пример 5.10. Конкатенация строк \ .^--^-.- - ^у--,;/-^-.^ ' ->«_. ч ' 3¾¾ » S=strcat('123','ABCDEFG') S = 123ABCDEFG
172 Глава 5 » whos Name Size Bytes Class S 1x7 14 char array Grand total is 7 elements using 14 bytes Однако в качестве аргументов этой функции могут выступать и символьные массивы, содержащие одинаковое количество строк. В этом случае результатом работы функции strcat является символьный массив, каждая строка которого получена как горизонтальная конкатенация соответствующих строк- операндов (пример 5. II). ГПример5:1иЙ:о$|э^ =^$£»f ?4$ЩЩ » S=strcat[[,123,;,ABC'],['5678';'abed']) S = 1235678 ABCabcd » whos Name Size Bytes Class S 2x7 28 char array Grand total is 14 elements using 28 bytes Аргументами функции strcat могут быть и массивы ячеек, содержащие строки разной длины. В этом случае результирующий массив также будет состоять из ячеек, полученных с помощью горизонтальной конкатенации содержимого соответствующих ячеек (пример 5.12). ;.Пример 5.12. Конкатенация массивов ячеек ■ ■■^■«■-ф ^■^■^^v.-b.^,.,.^^.^^ » S=strcat({'12-3',*ABCD'I,['45678','xz'}) S = '12345678' 'ABCDxz' » whos Name Size Bytes Class S 1x2 148 cell array Grand total is 16 elements using 148 bytes Применяя горизонтальную конкатенацию, не забывайте об одной тонкости ее выполнения — в отличие от аналогичной операции сцепления строк массива функция strcat игнорирует пробелы в конце строки (пример 5.13).
Обработка символьных данных 173 » strcatCC ','Новым ','Годом!') ans = СНовымГодом! » strcat('С1,1 Новым',' Годом! ') ans = С Новым Годом! » ['С ', 'Новым ','Годом!'! ans = С Новым Годом! » [' С.', ' Новым', ' Годом! ' ] ans = С Новым Годом! Кроме горизонтальной конкатенации строк MATLAB предлагает и вертикальную конкатенацию, выполняемую с помощью функции strvcat (пример 5.14). цПример 5.14.'Вертикальная конкатенация строк М$^:^^Ш^'^^^^^^М^ » S=strvcat('123','ABCDEFG') S = 123 ABCDEFG » whos Name Size Bytes Glass S 2x7 28 char array Grand total is 14 elements using 26 bytes В отличие от горизонтального присоединения операндов при вертикальной конкатенации "объединяемые" строки подписываются одна под другой, создавая столбец в результирующем массиве. Это происходит и в том случае, когда операндами являются массивы строк (пример 5.15). i Прим6р;5?15. Вертикально "•*'■ г??*.. >■ ] » S=strvcat(I'123';'ABC'],['5678';'abed']} S = 123
174 Глава 5 две 567S abed » whos Name Size Bytes Class S 4x4 32 char array Grand total is 16 elements using 32 bytes Вертикальная конкатенация массива ячеек, состоящего из строк, преобразует свой единственный операнд в символьный массив (пример 5.J6). г ' ' V- ;; .■...«....■v.»-.......».../.-;.^-,,»—".■..•■..■ : y...^........^^...^................^.^ .„, ; Пример 5.16. Вертикальная конкатенации массива ячееклйй t^ Д&д*:?",.-^1 '-л* ч щМ ;Л ™...,.-..fc..:si'...;;!j:'.i '......Г. i...^.s.a..%i:v.;.iVwtf.^.i.;W.i'i:.::.\.^ » S=strvcat(('123','ABCD'}) S = 123 ABCD » whos Name Size Bytes Class S 2x4 16 char array Grand total is 8 elements using 16 bytes Несмотря на то, что процедура горизонтальной конкатенации напоминает функцию с аналогичным названием из библиотеки С (раздел siring.h), возможности ее в системе MATLAB гораздо шире за счет использования операндов-массивов. 5.3. Сравнения символьных данных Так как символьные данные представлены в памяти компьютера числовыми кодами своих символов, упорядоченными в алфавитном порядке, то их можно сравнивать примерно как и значения числового типа. В- большинстве алгоритмических языков именно так и поступают, выясняя, равны или не равны сравниваемые строки, какая из них меньше или больше. Два последних соотношения позволяют определить порядок следования строк при их лексикографическом упорядочивании (т. е. при сортировке в алфавитном порядке). В большинстве систем программирования, конечно, возникают разного рода проблемы, связанные со сравнением русскоязычных строк или с преобразованием символьных данных к верхнему или нижнему регистрам. Например, в кодовой странице MS-DOS с номером 866 между кодами малых букв "п" и "р" затесались символы псевдографики, а коды букв "ё" и "Ё" расположены не на
Обработка символьных данных 175 своих законных местах. Такого же рода участь постигла буквы "ё" и "Ё" в кодовой странице Windows с номером 125L Функции сравнения символьных данных, представленные в MATLAB, производят проверку только на равенство или неравенство операндов, в качестве которых могут выступать не только строки, но и массивы строк. В последнем случае операция сравнения выполняется над каждой парой элементов с одинаковыми индексами. Результат каждого такого сравнения вырабатывает логический признак 1 (истина) в случае совпадения значений и логический признак о (ложь) в случае несовпадения. Если все промежуточные сравнения выработали единичные признаки, что свидетельствует об абсолютном тождестве сравниваемых данных, то функция возвращает логическое значение 1. Если хотя бы в одном промежуточном сравнении обнаружено расхождение, то функция возвращает логическое значение о. Если сравниваемые данные представлены массивами ячеек одинаковой размерности, то функция сравнения возвращает логический массив той же размерности, где каждый элемент равен 1 или о в зависимости от совпадения или несовпадения значений соответствующих ячеек. Для сравнения символьных данных язык MATLAB предлагает четыре функции: stremp, strempi, strnemp и stmempi. Первая из них производит посимвольную проверку на равенство или неравенство всех элементов сравниваемых операндов, вторая выполняет аналогичное сравнение, игнорируя разницу между кодами больших и малых букв, третья сравнивает только заданное количество начальных символов, четвертая сочетает в себе возможности второй и третьей (пример 5.17). %Сравне'ние векторов-строк » S1='ABCDEFGH'; » S2='ABCDefgh'; » ЭЗ-'АВСаЬс'; % Сравнение на абсолютное совпадение всех символов » stremp(S1,S2) ans = О % Сравнение с игнорированием разницы между большими и малыми буквами » strempi(S1,S2) ans = 1
176 Глава 5 1 » whos Name SI S2 S3 ans Size 1x8 1x8 1x6 lxl % Сравнение на абсолютное совпадение первых 3 символов » strncmp(Sl,S2,3) ans = Bytes Class 16 char array 16 char array 12 char array 1 logical array Grand total is 23 elements using 45 bytes' % Сравнение символьных массивов » SM1=['1234567';' ДБВГДЕЕ']; » SM2=['1234567';' АБВГдее1]; » strcmp(SMl,SM2) ans = 1 » strncmp(SMl,SM2,4) ans = 1 » strcrapi(SMl,SM2) ans = 0- » SM3=['123456';' АБВГДЕ']; » SM4=['123456';' ДБВгде']; » strcmpi(SM3,SM4) ans = 1 % Сравнение массивов символьных ячеек » SC1=[{Ч234'},{'ABCDEFGH'}] ; » SC2=[{'1235'},{'ABCDefgh'}]; » strcmp(SCl,SC2) ans = 0 0 » strcmpi(SCl,SC2) ans =■ 0. 1
Обработка символьных данных 177 » whos Name Size Bytes Class SCI 1x2 14 4 cell array SC2 1x2 144 cell array ans 1x2 2 logical array Grand total is 30 elements using 290 bytes » strncrep(SCl,SC2,3) ans = Обратите внимание на результаты сравнения массивов (smi, sm2) и (бмз, SM4) с помощью функции strcmpi. В операционной системе Windows ХР буквы "Ё" и "ё" сравниваются нормально, несмотря на то, что разница между их числовыми кодами отличается от разницы между числовыми кодами больших и малых букв русского алфавита. В предыдущих версиях MATLAB результат такого сравнения был противоположным. Одним из аргументов в операции сравнения может быть скалярная величина, и тогда она сопоставляется с каждым элементом второго аргумента — массива строк или ячеек. Возвращаемый результат в этом случае будет логическим массивом. К группе процедур сравнения следует отнести функции isspace и isletter, операндами которых могут быть строки, массивы строк или массивы символьных ячеек. Обе функции возвращают логический массив такой же размерности, как и размерность операнда. Функция isspace заносит в позицию результата, соответствующую каждому проверяемому символу, 1 (логическая истина) или о (логическая ложь) в зависимости от того, является или не является анализируемый символ белым пробелом. Множество белых пробелов составляют символы НТ (горизонтальная табуляция — код 0x09), LF (перевод строки — код Оход), VT (вертикальная табуляция — код Охов), FF (новая страница — код Охос), CR (возврат каретки — код OxOd) и настоящий пробел (код-0х2о). Функция isietter анализирует, является или не является проверяемый символ буквой (пример 5.18). [; Примё£5:18. Проверка наличия пробелов й символов в;«троке^й^ ".__; *": ! » isspace('С Новым Годом!') ans = Columns 1 through 11 01000001000 Columns 12 through 14 0 0 0
178 Глава 5 » isletter('С Новым Годом!'> ans = Columns 1 through 11 10111110111 Columns 12 through 14 110 » whos Name Size Bytes Class ans 1x14 14 logical array Grand total is 14 elements using 14 bytes 5.4. Поиск и замена Функции findstr и strf ind предназначены для поиска всех вхождений одной строки в другую (пример 5.19). Разница между ними заключается в том. что функция findstr демократичнее и позволяет задавать операнды в любом порядке — сначала более длинная строка, а потом более короткая, и наоборот. Функция strfind выполнена в стиле стандартов универсальных алгоритмических языков, и искомая подстрока обязательно должна быть представлена вторым аргументом. [ Пример 5". 1'9. ПриЬк в символьных данных • !'y^r ^-1 J ;'" » S1='00\- » S2='2O03'; » S3='100002'; » findstr(SI,S2) % Порядок операндов роли не играет ans = 2 »■ findstr(S2,SI) % Порядок операндов роли не играет ans = 2 » strfind(SI,S2) % Порядок операндов важен ans = [1 ■>> strfind(S2,Sl) % Порядок операндов важен ans — 2 » 33.= 400002 4-
Обработка символьных данных 179 » findstr (S3, S.I.) % Пример множественного вхождения ans = 2 .» whos Name SI S2 S3 ans 3 Size 1x2 lx<5 1x6 1x3 Bytes Class 4 char array В char array 12 char array 24 double array Приведенные выше функции возвращают результат поиска в виде числового массива типа double, каждый элемент которого определяет индекс символа, с которого обнаружено очередное вхождение. Другой вариант поиска можно осуществить в массиве строк или в массиве ячеек с помощью функции strmatch (пример 5.10). Ее особенность заключается в том, что в массиве, представленном первым аргументом, отыскиваются строки, начинающиеся со значения второго аргумента. Внутреннее вхождение поискового образа здесь во внимание не принимается. При добавлении третьего аргумента 'exact' функция strmatch возвращает номера только тех строк первого операнда, которые в точности совпадают с поисковым образом. | Пример 5.20. Поиск в символьных данных с использованием функции s/ I strmatch ~ ! % Поиск- в массиве строк %====,==== » SM=strvcat{"com','compare','computer') SM = corn compa re computer » strmatch('com',SM) % поиск строк, начинающихся с 'com' ans = 1 2 3 » strmatch('com',SM, 'exact') % поиск точного совпадения ans = 1
180 Глава 5 » S=423com'; » strmatch('com',S) % внутреннее вхождение игнорируется ans = U % Поиск в массиве ячеек ». SC={'com';'compare';'computer') SC = 'com' 'compare' 'computer' » strmatch('com',SC) ans = 1 2 3 » whos Name S SC SM ans Size 1x6 3x1 3x8 3x1 Bytes Class 12 char array 216 cell array 48 char array 24 double array Как можно заметить из приведенного примера, возвращаемое значение функции strmatch представлено числовым массивом типа double. Функция strrep(strl,str2,Str3) предназначена для поиска в строке strl всех вхождений заданной цепочки символов str2 и замены каждой из них новым значением str3 (пример 5.21). Если поиск не увенчался успехом, то функция strrep возвращает строку strl. Пример 5.21 ;„Поиск.и замена в символьных данных -1^^:.- V-= ti- *.-:> ^¾^ » S='12341234'; » Sl=strrep(S,'123','ABCD') 51 = ABCD4ABCD4 » S2=strrep(S,424','ABCD') 52 = 12341234
Обработка символьных данных 181 Замещающее значение может быть пустой строкой, и таким образом легко удалить ненужную цепочку символов (пример 5.22). I Пример ^22. Удаление цепочки символов --¾¾¾^¾¾¾¾^ . *'Щ:~*^'&Щ£%&^^ \ » S3=st.rrep (S, ' 123', " ) S3 = 44 Если один из аргументов функции strrep представлен массивом ячеек, то возвращаемый результат тоже преобразуется в массив ячеек (пример 5.23). (Пример 5.23. Поиск и замена в массиве ячеек ^^¾¾ £^--.- {?fc^£?£?&й£Г 4^.1 » Sl='12341234'; » S2=strrep(Sl,'123\ ( " )) 52 = ■44' » whos Name Size Bytes Class 51 1x8 16 char array 52 lxl 64 cell array Термин лексема обозначает цепочку символов, завершающуюся тем или иным разделителем. Например, в предложении лексемами являются слова, признаком конца которых могут быть разные разделители — пробелы, запятые, точки, тире и др. При разработке трансляторов довольно часто приходится выделять лексемы типа служебных слов, имен функций, операндов, выражений и т. п. Облегчить эту работу вам поможет функция strtok, основным аргументом которой является анализируемая строка. По умолчанию данная функция рассматривает в качестве символа-разделителя любой белый пробел. Выходных аргументов у этой функции два: lt,r]=strtok(S) В строку t заносится найденная лексема, а в с фоку г — оставшаяся часть строки s (пример 5.24). [Пример 5:24. Выделение лексем .."'- ' >■ ■* /'"* Л",г" ^-¾^^ " '* ' Щ^Щ » S='C Новым Годом!'; » [tl,rl]=strtok(S)
182 Глава 5 tl = G rl = Новым Годом! » [t2,r2]=strtok(rl) t2 = Новым г2 = Годом! » [t3,r3]=strtok(r2) t3 = Годом! r3 = Empty string: l-by-0 Второй необязательный аргумент функции strtok позволяет задать нестандартный набор символов-разделителей (пример 5.25). ; Пример 5.25. Выделение лексем с'нестандартными разделителями » S='a+b*c'; » [tl,rl]=strtok(S,'+*') tl = а rl = +b*c » [t2,r2]=strtok(rl,'+*') t2 = b r2 = *c » [ t3, r31 «strtok (i:2 ,■ + *') t3- = С r3 = Empty string: l-by-0
Обработка символьных данных 183 5.5. Преобразования к верхнему и нижнему регистрам Функция strcmpi позволяет сравнивать строки, игнорируя разницу между большими и малыми буквами. На самом деле для выполнения такой процедуры можно воспользоваться одним из двух алгоритмов — предварительно преобразовать коды всех символов к нижнему (т. е. к строчным буквам) или к верхнему (т. е. к прописным буквам) регистру, а затем произвести посимвольное сравнение. Такое преобразование, если оно понадобится в вашей программе, можно выполнить с помощью одной из функций — lower или upper (пример 5.26). I Пример 5.26. Преобразование регистра •• -%-г %%■*£-■ *%Щ >> lower('Happy New Year - С Новым Годом!1) апз = happy new year - с новым годом! » upper ('Happy New Year - С Нозьел Годом!') ans = HAPPY NEW YEAR - С Новым Годом! MATLAB 7, в отличие от предыдущих версий, правильно обрабатывает строки, содержащие буквы "ё" и "Ё": » lower('ЁЛКА') ans = ёлка » upper('ёлка') ans = EUKft 5.6. Преобразования строк и чисел Значения числовых скалярных величин и элементов массивов типа double могут быть преобразованы из машинного представления в соответствующие символьные строки с помощью функций num2str и int2str. Первая из них преобразует компоненты единственного аргумента с четырьмя цифрами в дробной части (пример 5.27). 7 Чак SB9
184 Глава 5 » num2str(pi) arts = 3.1416 » whos Name Size Bytes ans 1x6 12 .Grand total is 6 elements using 12 bytes Второй необязательный аргумент в этой функции определяет количество цифр в дробной части результата, однако бесполезно задавать его значение большим, чем это предусмотрено форматом double (пример 5.28). I Пример 5.28. Преобразование; числа в'чйрс^^^^НнЬй'тотност^!^^!1^^ » num2str(pi,10) ans = 3.141592654 » num2str(pi,20) % Больше 17 цифр формат double не хранит! ans = 3.1415926535897931 Аргумент функции num2str может быть и комплексным числом (пример 5.29). !'"'Пример^5;2£::Пре0бразовШй'е'-кЬч^^ » x=sqrt(-2) x = 0 + 1.4142i » num2str(x, 10) ans = 0+1.414213562i » whos Name Size ans 1x14 x lxl Grand total is 15 elements Class char array Bytes Class 28 char array 16 double array (complex) using 44 bytes
Обработка символьных данных 185 Вообще, функция num2str допускает гибкое управление форматом преобразования числовых данных (пример 5.30) подобно тому, как это делает процедура sprint f. [Пр^^р^^^ spj » num2str(pi,'pi=%6.2f') ans = pi= 3.14 » whos Name Size Bytes Class ans 1x9 18 char array Grand total is 9 elements using IB- bytes Функция int2str предварительно округляет компоненты своего числового аргумента до целых чисел и сохраняет в возвращаемом массиве строк все значащие цифры. Иногда обилие нулей может удивить даже опытных программистов (пример 5.31). а встроку^К*4^ftW-.n4s-tTl Пример 5.31. Преобразование целого числа в строку » х=[[0'.1 0.5 0.8];[100.1 100.5 100.8]] х = 0.1000 0.5000 0.8000 100.1000 100.5000 100.8000 » int2str{x) ans = 0 11 100 101 101 » whos Name Size Bytes Class x 2x3 48 double array ans 2x13 52 char array Grand total is 32 elements using 100. bytes » x=NaN; » int2str(x) ans = NaN » x=Inf ; » int2str(x)
186 Глава 5 ans = Inf » x=realmin x = 2.2251e-308 »■ int2str(x) ans = 0 » x=realmax x = 1.7977e+30.8 » int2str(x) ans = 1797693134862315700000000000000000000000000000000000000000000000000000000 OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO 0000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000 » length (ans) ans = 309 Если в качестве аргумента функции int2str задано комплексное число, то преобразование выполняется только над вещественной частью (пример 532). ; Пример 5.32. Преобразование комплексного числа в строку "' .'£''■"* 'Й?.' ! функцией infc2s.tr1 'А\.. >",■- - ,-■,.■■ £_ .- ";> r-.-.s^ ^¾ . й';р. в| » x=sqrt(-2)+5.8 х = 5.8000 + 1.4142i » int2str(x) ans = 6 Обратные преобразования числовых данных из символьного представления в машинный формат типа double выполняются с помощью функций str2double и str2num. Первая из них осуществляет преобразование единственного значения, в символьном представлении которого использованы все
Обработка символьных данных 1В7 допустимые знаки — цифры, точка, плюс или минус, буква е, предшествующая порядку числа, запятые, разделяющие число тысяч, буквы i или j, символизирующие мнимую часть комплексного числа (пример 5.33). ■ Пример 5.33. Преобразование строки в число :-.^^i,'f^'Myj-yr^.' -£*■■«■■..№.■;;- .■< : ,...:.;.?л;.ж:,:;...л„:^:.,.й;;../.^ , ....... : 1..;.; ::..^::¾¾.¾ £ :....■ а«5|ЯЖлц^й?;'«Ллййл- ... '^-.аад ». Sl=str2double('3.14ISS265') SI = 3.1416 » Sl=str2double('1,000, 000') SI = 10000CO » Sl=str2double{'le6'> SI = 1000000 » Sl=str2double{'1-2j') SI = 1.0000 - 2.0000i Функция str2num позволяет преобразовать числовые данные, представленные элементами символьного массива (пример 5.34). I. Пример 5.34. Преобразование символьного массива в число'■.'- ""*■■'... :j » S=['1 2'; ■3 4'] S = 1 2 3 4 » str2num(S) ans = 1 2 3 4 » whos Name Size Bytes Class S 2x3 12 char array ans 2x2 32 double array Grand total is 10 elements using 44 bytes
188 Глава 5 В символьной записи чисел не должно быть лишних пробелов, т. к. это может привести к труднообнаруживаемой ошибке (пример 5.35). L Пример 5.35. Влияние пробелов на преобразование строки в число i$fei/i&£Sl » x=str2num('1-2 j') х = 1.0000 - 2.0000i » y=str2num('1 -2j'} У = 1.0000 0 - 2.0000i » whos Name Size Bytes Class x lxl 16 double array (complex) у 1x2 32 double array (complex) В первом случае результатом преобразования является единственное комплексное число, тогда как во втором случае — вектор из двух чисел. В отдельную группу функций следует выделить процедуры преобразования числовых данных, символьное представление которых зависит от используемой системы счисления, — dec2bin, dec2hex, dec2base, bin2dec, hex2dec, base2dec, hex2num. Шесть первых функций имеют дело с целыми десятичными числами (dec — от англ. decimal) и их символьным представлением в двоичной (bin — от англ. binary) и шестнадцатеричной (hex — от англ. hexadecimal) системах, а также в любой другой системе счисления с заданным основанием (base) в диапазоне от 2 до 36. Цифра 2 в названии каждой функции ассоциируется с предлогом "в" (англ. two — "два" и to — "в" звучат одинаково). Эти функции осуществляют прямое и обратное преобразования между целыми десятичными числами формата double и соответствующим символьным представлением этих же чисел в заданной системе счисления. Функция dec2base очень напоминает функцию itoa из библиотеки C++. Для тех, кто недоумевает по поводу диапазона основания системы счисления от 2 до 36, поясним, что для обозначения цифр в системах с основанием больше 10 используются буквы латинского алфавита. Поэтому 10 цифр и 26 букв латинского алфавита обеспечивают представление чисел в системе с максимальным основанием 36. Функция dec2bin[N> преобразует целочисленный положительный аргумент, не превосходящий 252, в строку с двоичным представлением аргумента (пример 5.36).
Обработка символьных данных 189 » dec2bin(792) % Перевод в двоичную систему ans = 1100011000 Второй необязательный аргумент функции dec2bin(N,k> задает количество двоичных цифр, которое следует сохранить в результате. Его не имеет смысла указывать меньше, чем фактическое количество разрядов в двоичном представлении числа: » dec2bin(792,5) % Перевод в двоичную систему с 5 цифрами ans = 1100011000 » dec2bin(792,12) % Перевод в двоичную систему с 12 цифрами ans = 001100011000 Если основной аргумент функции dec2bin представлен числовым массивом, то результат преобразования будет получен в виде массива строк, длина которых выровнена по максимальному числу: » a=[148 1023,-525 792]; » dec2bin(a) % Перевод в двоичную систему числового массива ans = 0010010100 1000001101 1111111111 1100011000 Аналогичный перевод в строку с шестнадцатеричным представлением аргумента выполняет функция dec2hex (пример 5.37). ! Пример 5.37. Перевод числа в шестнадцатеричную.систему ^¾¾^1¾¾¾,;><•£''"'; » dec2hex(792) % Перевод в шестнадцатеричную систему ans = 318 » dec2hex(792,5) % Перевод в шестнадцатеричную систему с 5 цифрами ans = 00318 » а=[148 1023,-525 792]; » dec2hex(a) % Перевод в шестнадцатеричную систему массива чисел
190 Глава 5 ans = 094 20D 3FF 318 При переводе целого десятичного числа в систему с основанием р значение р задается вторым аргументом функции dec2base. Необязательный третий аргумент определяет количество цифр в результате (пример 5.38). ! Пример 5.38j Перевод числа в произвольную систему сч^слейий v ■■< -_гц 4f *; р,^з » dec2base(792,5) % Перевод в пятеричную систему ans = 11132 » dec2base(792,5,8) % Перевод в пятеричную систему с 8 цифрами ans = 00011132 ФуНКЦИИ bin2dec, hex2dec И base2dec Преобразуют строку С СИМВОЛЬНОЙ записью числа в двоичной, шестиалцатеричнои или произвольной системе счисления в машинный формат целого числа типа double (пример 5.39). : Пример 5.39. Преобразование числа в десятичнунр систему 11¾.¾¾¾^¾^)^ » bin2dec('1100011000') ans = 792 » hex2de.c('3l8') ans = 792 » base2dec(,11132',5) ans = 792 Если аргументом этих функций является массив строк, то каждая строка рассматривается как символьный эквивалент целого положительного числа в соответствующей системе счисления (пример 5.40).
Обработка символьных данных 191 » bin2dec(['101100';'001101']) sns = 44 13 » whos Name Size Bytes Class ans 2x1 16 double array Вещественное число в формате типа double занимает 8 байтов оперативной памяти и может быть компактно записано с помощью 16 шестнадцатеричных цифр* включающих знак, порядок и мантиссу числа в соответствии со стандартом IEEE — 1 бит на знак, 11 битов на порядок в дополнительном коде и 52 бита на мантиссу. В такой записи, например, число я на IBM-совместимых компьютерах выглядит следующим образом — 400921FB54442D18. Для преобразования такой строки символов в число используется функция hex2num (пример 5.41). » format long » hex2num('40.09211^544420181) ans- = 3.14159265358979 Если аргумент функции hex2num содержит менее 16 символов, то он дополняется справа нулями. Функции mat2str и str2mat занимаются преобразованиями между символьной записью двумерных числовых матриц и их машинным представлением (пример 5.42). {«Пример 5;4Z:^ ;■ "':.;-: *'- ' 4-|;i » х=(1 2; 3 4] х = 1 2 3 4 » y=mat2str{x)
192 ' Глава 5 У = tl 2;3 4] ■» z=str2mat('[1 2;3 4]') г = [1 2;3 4] » whos Name X У z Size 2x2 1x9 1x9 Bytes 32 18. 18 Class double array char array char array Grand total is 22 elements using 68 bytes » x=[l 2;3 4] В целесообразность последней процедуры верится с трудом. 5.7. Форматные преобразования (sprintf, sscanf) Идеологию функций преобразования числовых и символьных данных по заданному формату MATLAB заимствовал из языка С, почти полностью сохранив набор соответствующих спецификаций. Конечно, определенную особенность вносит то, что элементом преобразуемых данных может быть массив. Но тогда действие соответствующего форматного указателя распространяется на каждый элемент массива. Преобразование списка данных (ai, а2, ...) по формату fmt с записью результата в строку s выполняется с помощью функции sprintf: [s,s_err] = sprintf{fmt,al,a2,...) Кроме результата преобразования функция sprintf может выработать сообщение об ошибке во время выполнения операции, которое заносится в строку s_err. При нормальном завершении операции вместо сообщения об ошибке выдается пустая строка, которую можно проигнорировать, если обратиться к функции с единственным выходным параметром: s = sprintf(fmt,al,a2, ...) Однако ошибка, обнаруженная при выполнении преобразования, может привести к получению пустой результирующей строки: » sprintf С %ld\ pi) ans = 3.14l593e+000 » sprintf (' %lf ,pi)
Обработка символьных данных 193 ans = Empty string: l-by-0 Формат %lf, допустимый в С и обеспечивающий вывод вещественных чисел с удвоенной точностью, в системе MATLAB считается недопустимым и приводит К сообщению Об ошибке s_err=Invalid format. Строка формата fmt задает шаблон преобразования, состоящий из спецификаций, начинающихся с символа %, и набора литеральных символов, переносимых без всяких изменений из строки формата в результат. Каждая спецификация, управляющая способом преобразования, может содержать до 5 следующих компонентов: % [флажки] [ширина] [.точность] [{b, t}]cc Обязательными среди них являются начальный символ (%) и завершающая буква (ее). Флажки задаются как комбинация от одного до трех символов из набора (-, +,"", #, о). Символ - устанавливает левый прижим. По умолчанию преобразуемое значение прижимается к правой границе поля заданной ширины. Символ + устанавливает режим обязательного вывода знака числа (даже если преобразуемые числа положительны). Символ " " (пробел) устанавливает режим вывода знака положительного числа пробелом (по умолчанию на знак положительного числа специальная позиция не отводится). Символ # влияет на вывод восьмеричных, шестнадцатеричных и вещественных чисел. Перед восьмеричными числами выводится о, перед шестнадцате- ричнымй числами — префикс Ох или ох. В символьную запись вещественных чисел, преобразуемых по форматам £, е и Е, обязательно включается десятичная точка (по умолчанию она опускается, если дробная часть равна 0). В символьной записи вещественных чисел, преобразуемых по форматам g и G, не удаляются лидирующие нули и всегда включается десятичная точка. Символ о при правом прижиме чисел включает режим вывода лидирующих нулей. Ниже приведено несколько примеров, демонстрирующих влияние флажков при выводе целых чисел (пример 5.43). ;.Лрймёр;.5Ш^ррматнйй вывод целых 41106¾¾¾^¾¾¾^ 1$ф-г2фр*Щ^^Ф&\ » sprintf С%-5d %+5d %05d\123,123,123) ans = 123 +123 00123 » sprintf <'%x: %-№X\123,123)
194 Глава 5 ans = 7b 0X7B » sprintf{'% d',123) ans = 123 » sprintf('% d',-123) ans = -123 Ширина, задаваемая целым числом, определяет количество позиций (символов), которое отводится под преобразуемое значение. Точность, также задаваемая целым числом, определяет количество дробных цифр, сохраняемых в преобразованном значении: ■» sprintf('%10.6f' ,.pi) ans = 3.141593 Символ а, завершающий форматную спецификацию, определяет вид преобразованного значения и должен согласовываться с типом преобразуемого данного. Возможные варианты этого символа приведены в табл. 5.1. Таблица 5.1 Спецификатор Формат результата %с Единственный символ %d Целое десятичное число со знаком %е Вещественное число в форме с плавающей запятой (порядок идентифицирует буква е) %Е Вещественное число в форме с плавающей запятой (порядок идентифицирует буква е) %f Вещественное число в форме с фиксированной запятой %д Компактная форма числа с фиксированной или плавающей запятой SG Компактная форма числа с фиксированной или плавающей запятой %о Целое восьмеричное число без знака %s Строка символов %ч Целое десятичное число без знака %х Целое шестнадцатеричное число с малыми буквами а—f %х Целое шестнадцатеричное число с большими буквами A—F
Обработка символьных данных 195 Спецификаторы %.d, %u, %о, %х и %х имеет смысл применять к целочисленным значениям (хотя и представленным в оперативной памяти в формате double). Если соответствующий элемент списка не является целым числом, то MATLAB заменяет целочисленную спецификацию на формат вещественного числа: » sprintf('%d',pi} ans = 3.141593е+000 Однако после округления спецификатор %d действует нормально: » sprintf('%d',round(pi)) ans = 3. Символ ь или t, предшествующий символу-спецификатору, позволяет преобразовать в восьмеричный или шестнадцатеричный формат вещественные числа стандарта [ЕЕЕ. Они используются в сочетании с форматными указателями %о, %х или %х. Однако результат их применения может удивить в связи с перестановкой байтов, характерной для IBM-совместимых компьютеров (пример 5.44). *7'г»ида^::^™:^т;-:*^^ " -^--.4----¾¾^^.¾ ;.Пример 5.44. Форматный вывод с преобразованием,системы счисления i ■ * _ ■ » sprintf('%bx',pi) ans = 182d4454fb210940 % Здесь переставлены байты » format long » hex2num(,400921EB54442D18') ans = 3.14159265358979 » sprintf('%bx'fl) \ ans = 000000000000f03f » hex2num('3ff0000000000000') ans = 1 » sprintf('%tx',l) ans = 3f800000
196 Глава 5 Все символы, включенные в состав строки fmt и не относящиеся к форматным спецификациям, являются литералами, которые без изменения переносятся в результирующую строку: » sprintf(,nM=%10.8f'/pi) ans = пи=3.14159265 Среди литералов могут присутствовать управляющие символы и специальные знаки, запись которых выполняется в соответствии с правилами языка С (табл. 5.2). Таблица 5.2 Символ \ь \f \п \г \t \\ V %% Назначение Удаление предшествующего символа (Backspace) Перевод страницы (Form feed) Перевод строки (New line) Возврат каретки (Carriage return) Горизонтальная табуляция (Horizontal tab) Обратная косая черта (Backslash) Одинарная кавычка (') Процент(%) Обратная операция по извлечению данных из строки s, сформированной функцией sprintf, выполняется с помощью функции sscanf: A = sscanf(s,fmt) Этот вариант вызова обеспечивает выборку всех данных и их обратное преобразование из символьного представления в машинное в соответствии с форматными указателями строки fmt. Форматные спецификации здесь те же самые, что и при преобразовании в строку (см. табл. 5.1), хотя некоторые детали, характерные для вывода данных (прижим, точность, префиксы и т. п.), в обратном преобразовании не используются. Среди дополнительных средств управления форматом выделим использование: П флажка, задаваемого символом *, обеспечивающего пропуск очередного данного в строке s; П форматов %hd, %id и %ig, позволяющих преобразовать извлекаемое число в машинный формат короткого целого (%hd), длинного целого (%id) или вещественного числа с удвоенной точностью (%lg);.
Обработка символьных данных 197 П формата %[sis2... ], обеспечивающего извлечение только тех символов из строки s, которые перечислены в квадратных скобках; П формата %[~sis2... ], обеспечивающего извлечение только тех символов из строки s, которые не перечислены в квадратных скобках. Для программистов, работавших на языке С, будет довольно непривычно увидеть следующее использование единственного форматного указателя (пример 5.45). гЛримёр-5:45.''Испол£^ I -41.-. .г.л^.. .. . ....tl,?j» -. ...Л .'.*..№ ji..-.. «vis.Яti?ni\..;*,?.,f.r'rff.it, bir(AvAV<»i'> ДЯ1 «Vi. /**.»«-й»«тЛ; ;П £vt».'ir ¥frtf*?t,tjf ,t r№№i№t » s = '2.7183 3.1416'; » A = sscanf(s,*%f') A = 2.7183 3.1416 Однако ведь и при прямом преобразовании в строку для массива а требовалась тоже только одна спецификация формата: » sl=sprintf('%f ',А) si = 2.718300 3.141600 Обратите внимание на использование литерального пробела в формате. Без него оба числовых значения оказались бы "склеенными", и для их разделения потребовались бы определенные усилия (пример 5.46). ЬПри»4ер,5:46:.О.теутствие-разделмхе^^ » sl=sprintf('%f', А) si = 2.7183003.141600 >i> s2=sl(l:B) s2 = 2.718300 » s3=sl(9:end) s3 = 3.141600
198 Глава 5 Впрочем, склейки можно было бы избежать за счет использования ширины, точности и прижима: » sl=sprintf{'%-8.4f' ,А) si = 2.7183 3.1.416 Функция sscanf допускает и другие варианты вызова, обеспечивающие извлечение только заданного количества данных или их извлечение в цикле: A = sscanf(s,fmt,size) [A,count,s_err,nextindex] = . sscanf(s,fmt} 5.8. Регулярные выражения и поиск В разд. 5.4 рассматривались процедуры поиска заданного текста. При этом разрешались две возможности. Кроме абсолютного совпадения искомого фрагмента с заданным текстом допускалось игнорировать разницу между большими и малыми буквами. Более широкие возможности для поиска в текстовом документе предоставляют так называемые регулярные выражения. В шаблоне, формируемом с помощью регулярных выражений, разрешается задавать не только те символы, которые должны присутствовать в искомом фрагменте. Например, если мы собираемся извлечь из текста семизначный номер телефона, то можно составить шаблон поиска следующим образом: "три_цифры тире две_цифрьг тире две_цифры". Или мы точно не знаем фамилию человека — то ли "Корягин", то ли "Калягин". В этом случае может помочь поисковый шаблон, в котором указано, что фамилия начинается с буквы "К", после нее следуют две какие-то буквы, а окончание имеет вид "ягин". Это позволит найти те данные, значения которых мы точно не знаем. Нечто похожее используют программисты, когда производят поиск файлов по некоторым шаблонам, задаваемым в фильтрах поиска. Например, показать все файлы с расширением ерр — шаблон поиска имеет вид *.срр. Символ * заменяет собой произвольную цепочку символов, расположенную перед четырьмя указанными. Шаблон поиска с применением регулярных выражений представляет собой строку или массив ячеек строк. Наряду с заранее известными символами в составе шаблона допускается использование следующих управляющих конструкций: П точка (.) — для указания позиции любого символа, включая и белый пробел. Для указания позиции, в которой искомый текст может содержать точку, Используется пара символов \.;
Обработка символьных данных 199 О Vw — для указания позиции, в которой может находиться буква, цифра или подчерк, т. е. те символы, которые участвуют в конструировании слов; П \w — для указания позиции, в которой может находиться любой символ, кроме буквы, цифры или символа подчеркивания; П \s — для указания позиции, в которой может находиться белый пробел; П \s — для указания позиции, в которой может находиться любой символ кроме белого пробела; П \d — для указания позиции, в которой может находиться цифра; □ \D — для указания позиции, в которой может находиться любой символ, кроме цифры; П [sis2.. -skj — для указания позиции, в которой может находиться любой из символов, перечисленных в квадратных скобках; О .[nsis2.. .sk] — для указания позиции, в которой может находиться любой из символов, кроме перечисленных в квадратных скобках. Когда диапазон символов, указываемых в квадратных скобках, непрерывен, то можно ограничиться заданием начального и конечного символов: [abede] = [a-el Шаблон поиска оформляется в виде строки, в которой указанные выше управляющие символы могут чередоваться с обычными символами. Например, шаблон вида ' w*ko\s' означает, что мы собираемся искать слово, оканчивающееся буквами "ко", вслед за которыми следует пробел. Заданным буквам может предшествовать любая цепочка символов, включающая буквы, цифры и символы подчеркивания. Обозначим через r, ri, R2 элементарные регулярные выражения, образованные из перечисленных выше конструкций. Их можно объединять в более сложные шаблоны поиска, выписывая друг за другом, объединяя в круглые скобки или сопровождая дополнительными указаниями следующего вида: П (R) * — выражение r может повторяться 0 или более раз; П (R) + — выражение r может повторяться I или более раз; П (R) ? — выражение r может повторяться 0 или 1 раз; О R{n,m} — выражение r должно повторяться от пдо траз; П R(n} — выражение r должно повторяться ровно п раз; П R(n, ) — выражение r должно повторяться п или более раз; П (R11R2) — искомый фрагмент может содержать тексты, удовлетворяющие либо шаблону ri, либо шаблону кг;
200 Глава 5 D "R - искомый фрагмент должен находиться в начале строки; П r$ — искомый фрагмент должен находиться в конце строки; П \<r — искомый фрагмент должен находиться в начале слова; П r\> — искомый фрагмент должен находиться в конце слова. Для организации поиска фрагментов текста, удовлетворяющих заданному шаблону, MATLAB предлагает три функции: П regexp — поиск всех фрагментов в заданной строке; П regexpi — поиск всех фрагментов в заданной строке с игнорированием разницы между большими и малыми буквами; П regexprep — поиск фрагментов и их замена другим контекстом. Две первые функции допускают задание от двух до восьми аргументов: П первый параметр (обязательный) определяет строку, в которой организуется поиск; D второй параметр (обязательный) представляет шаблон поиска; П все последующие параметры необязательные. Они задаются строками ■match', 'start', 'end', "tokens', 'tokenExtents', 'names', которые определяют перечень возвращаемых результатов поиска. Если ни один из необязательных параметров в обращении не задан, то функции поиска возвращают начальные индексы найденных фрагментов: » regexp('123_abc 45б_78', *\d(3)') ans = 1 9 Если задан единственный дополнительный параметр 'match', то функция regexp возвращает текст найденных фрагментов: » regexp('123_abc 456_78','\d{3)','match') ans = 423' '456' Необязательный параметр 'start* позволяет дополнительно получить индекс символа, с которого начинается найденный фрагмент: » [m s]=regexp('123_abc 45б_78','\d{3}','match','start') т. = 423' '456' ■s = 1 9
Обработка символьных данных 201 Перестановка местами необязательных параметров приводит к аналогичной перестановке возвращаемых результатов: » [m sl=regexp('123_abc 4S6_78','\d{3)','start','match'} т = 1 9 s = 423' '456' Необязательный параметр 'end' включает в состав возвращаемых результатов индекс последнего символа найденного фрагмента: » [m indl ind2]=regexp('123_abc 456J78','\d(3}•,'match','start','end') m = 423' '456' indl = 1 9 ind2 = 3 11 Приведем пример 5.47. [Пример 5.47. Поис^ поэлементарны ■ .f " > j » s ='abCD_ 123#'; » [mat ind]=regexp(s,'Xs','match','start') mat = i i ind = 6 » [mat indj=regexp(s,'\S','match','start') mat = 'a' 'b' 'C 'D' '_' 4' '2' '3' '#' ind = 12345769 10 » [mat ind]=regexp(s,'\d','match','start') mat = 4' '2' '3' ind = 7 8 9
202 Глава 5 » [mat ind]=regexp(s, '\D', 'match', 'start') mat = ■a' 'b' 'C 'D' '_' ' ' '#' ind = 1 2 3 4 5 6 10 » [mat ind]=regexpCs,'\w','match','start') mat = ■a* 'b' 'C 'D' '_' '1' '2' '3' ind = 1234 5. 789 » [mat ind] =regexp (s, '\W, 'match', 'start') mat = , . ,#. ind = 6. 10 Тексты, в которых производится поиск, могут содержать и русские буквы (пример 5.48). I Пример 5.48. Использование кириллицы в;.регулярных выражениях -1 ■■> * Ч » str='Li;apb, царевич, король, королевич'; » pat='ap|op'; S R1 или R2 » regexp(str,pat) ans = 2 8 17 25 » раЫ='ич\>"; i » regexp(str,patl) % R в конде слова ans = 12 31 » pat3="4aap' ; » regexpi(str,pat3) %R в начале строки ans = 1 » раМ='ич$'; » regexpi(str,pat4) % R в конце строки
Обработка символьных данных 203 апз = 31 » pat2='\<цар'; » regexpi(str,pat2) % R з начале слова ans = 1 7 Параметр ■ tokens • используется для выделения лексем — цепочек символов, заключенных между заданными разделителями. Продемонстрируем это на примере из файла помощи, где лексемой считается цепочка символов, расположенных между буквами s: » str = 'six sides of a hexagon'; » pat = 's(\w*}s'; % Шаблон для поиска » [m s t]=regexp(str,pat,'match','start', 'tokens') m = % Найденный фрагмент % Начальный индекс % Массив янеек для лексем % Выделенная лексема 'sides' s = 5 t = (lxl » t(l) ans = •ide' » whos Name ans m pat s str t ce ul} Size lxl lxl 1x7 lxl 1x22 lxl Bytes 66 70 14 8 44 Class cell array cell array char array double array char array 126 cell array Мы могли бы заменить ограничитель 's' набором знаков арифметических операций и круглыми скобками для того, чтобы выделить операнды в формуле. Применение регулярных выражений расширяет возможности стандартных функций поиска — мы можем осуществить поиск и выделение подстрок текста, удовлетворяющих довольно сложным запросам. Наряду с этим имеется возможность произвести нестандартную замену найденного фрагмента с помощью функции regexprep.
204 Глава 5 В простейшем случае функция использует три обязательных аргумента — строка, в которой ищется фрагмент, шаблон поиска, которому должен удовлетворять найденный фрагмент, и текст замены: » s='H думаю, он думает, мы думаем'; » pat='дума'; » regexprep(s,pat,'по') ans = Я пою, он поет, мы поем По умолчанию процесс поиска фрагмента учитывает разницу между большими и малыми буквами: » 5='Я ДУМАЮ, он ДУмает, они думают'; » regexprep{s, pat,'по') ans = Я ДУМАЮ, он ДУмает, они поют С помощью дополнительного параметра 'ignorecase' включается режим игнорирования этой разницы: » regexprep(s, pat,'по','ignorecase') ans = Я поЮ, он поет, они поют Дополнительный параметр 'once' указывает, что замене подлежит только первый найденный фрагмент: » regexprep (s, pat, * по.', ' ignorecase', ' once') ans = Я поЮ, он ДУмает, они думают Процесс замены может использовать информацию о больших и малых буквах. При задании необязательного параметра 'preservecase' в заменяемых фрагментах сохраняются регистры заменяемых символов: » s='A_b_C_d_123'; » pat='[A-Z]'; » regexprep(s,pat,'qwerty','preservecase') ans = QWERTY_qwerty_QWERTY_qwerty_123 Аналогичная операция правильно выполняется и при замене символов русского алфавита: » s='Aa_B6_123' ; » pat='[А-Я]';
Обработка символьных данных 205 » regexprep(s, pat,'эЮя','preservecase') ans = ЭЮЯэюя_ЭЮЯэюя_12 3 Однако если шаблон поиска расширить до нескольких букв, то результат замены выглядит следующим образом: » s='Aa_B6_123'; » pat='[А-Я]* * ; » regexprep (s, pat, ' эЮя', ' preservecase ') ans = Эюя_Эюя_123 Мы перебрали различные комбинации регистров заменяемых и замещающих букв, меняли длины старых и новых фрагментов, однако предсказать результаты замен с использованием параметра 'preservecase' не удалось. Сулите сами: » s='AbcD_aBCd'; » pat-'[A-Z]*'; » regexprep(s,pat,'zx1,'preservecase') ans = zx_zx » regexprep(s,pat,'Zx','preservecase') ans = Zx_Zx » regexprep(s, pat, 'zX', 'preservecase *) ans = zX_zX » regexprep(s,pat,'EFgh','preservecase') ans = EFgh_EFgh » regexprep(s,pat,'efgh','preservecase') ans = efgh_efgh » s='ABCD_abcd'; » regexprep(s, pat,'efgh','preservecase') ans = EFGH_efgh » regexprep(s,pat,'EFgh','preservecase')
206 Глава 5 ans = EFGH_efgh » regexprep(s, pat,'EFGH', 'preservecase') ans = EFGH_efgh » s='Abcd_aBCD'; » regexprep[s,pat,'EFGH','preservecase') ans = Efgh_EFGH » regexprep(s,pat,'EFgh','preservecase') ans = Efgh_J5Fgh Очень похоже на то, что алгоритм до конца не продуман.
Глава 6 Работа с файлами Как правило, файлы представляют собой именованные области внешней (дисковой) памяти, с которыми программы могут обмениваться информацией. Необходимость в таких обменах возникает в разных ситуациях. Иногда объем оперативной памяти недостаточен для хранения нужной информации, и тогда приходится прибегать к услугам внешней памяти, записывая туда очередную порцию накопленных данных. В другой ситуации приложение может воспользоваться своими же данными, ранее записанными на диск или полученными в результате работы других программ. Вообще говоря, поставщиками или потребителями данных, с которыми наша программа вступает в контакт, могут быть не только дисковые файлы, но и файлы- устройства: диеплей, принтер, графопостроитель, сканер, клавиатура, каналы связи и т. п. Данная глава посвящена работе с дисковыми файлами, хотя обслуживание файлов-устройств происходит по аналогичной схеме. Оценивая ключевые аспекты процесса обмена данными, можно сказать, что работа с файлами в основном ограничивается тремя-четырьмя операциями: П выделение ресурсов и приведение файла в состояние готовности к обмену (именно это скрывается за термином открыть фаСш); П чтение (ввод из файла) или запись (вывод в файл) очередной порции данных; П возврат выделенных ресурсов и завершение неоконченных операций (этому соответствует термин закрыть файл). К числу наиболее важных моментов, связанных с обменом информацией, следует отнести формат представления данных на внешнем носителе. В большинстве своем почти все системы программирования (и MATLAB в этом смысле — не исключение) используют два формата данных — текстовые и двоичные. Текстовые или символьные данные состоят из строк,- похожих на те, которые мы набираем при вводе с клавиатуры или видим при выводе на экране дисплея. Для текстовых данных характерна переменная длина строки, завершающейся невидимым признаком конца (обычно эту функцию выпбл-
208 Глава 6 няют символы типа CR — возврат каретки, LF — перевод строки). Кроме того, числовые данные в строках представлены в естественном для человека виде. Это означает, что при вводе символьных данных служебные программы преобразуют числовую информацию во внутренний формат компьютера, а при выводе работают другие сервисные программы, которые преобразуют данные из машинного формата в приемлемый для человека вид. Из-за переменной длины строк обмен с текстовыми наборами данных приходится вести последовательно — строка за строкой. Ведь для того чтобы определить, где в наборе данных находится строка с заданным номером, пришлось бы перебирать байт за байтом все символы предшествующих строк. Как правило, объем информации, хранящейся в символьном наборе данных, заметно превышает длину той же информации в машинном формате. В основном это относится к данным числового типа. Например, число 71=3.14159265358979 в символьном представлении занимает 16 байтов, тогда как с таким же количеством значащих цифр его машинный эквивалент требует 8 байтов. Таким образом, текстовое представление данных имеет ряд минусов — оно менее эффективно по объему используемой памяти, требует дополнительных затрат на преобразование между машинным и символьным форматами, допускает только последовательный обмен между программой и внешним носителем. Однако главные преимущества текстовых данных заключаются в их естественности для восприятия человеком и в независимости их представления от компьютера и операционной системы. Последнее обстоятельство очень важно при передаче данных между различными вычислительными платформами. Информация, которая хранится в двоичных наборах данных, может иметь совершенно разную природу. Это могут быть и символьные данные с 8- или 16-разрядной кодировкой символов, и числовые данные в машинном формате, и графические образы в одном из многочисленных форматов (PCX, BMP, JPG, TIF и т. д.), и закодированные звуки, и многое другое. В отличие от текстовой информации, в байтах двоичного набора может встретиться любая двоичная комбинация, поэтому здесь отсутствует понятие управляющих кодов, таких как CR, LF, Tab и т. п. Обмен информацией с двоичными наборами данных не требует каких-либо преобразований. Поэтому он выполняется быстрее и связан с меньшими объемами памяти. В отличие от текстовых файлов, обмен данными с двоичными файлами выполняется порциями заданной длины. Поэтому в зависимости от природы информации, хранящейся в двоичных файлах, здесь имеется возможность прямого доступа к нужной порции данных. Таким образом, если файл предназначен для временного хранения информации, используемой только программой, и его содержимое не будет переноситься на компьютеры другого типа, предпочтение следует отдавать двоичным файлам.
Работа с файлами 209 6.1. Подготовка файла к работе Файлы открывают с помощью функции fopen, которая в случае удачного завершения возвращает целочисленный положительный идентификатор файла fid (в дальнейшем мы будем называть его номером файла). В простейшем варианте вызова указывается единственный входной аргумент — имя открываемого файла: f_id = fopen(,name_file'); В качестве имени открываемого файла может быть задано короткое имя, и тогда система пытается отыскать его сначала в рабочем каталоге, а затем производит поиск по всем каталогам, доступным пакету MATLAB. Если вы задаете полную спецификацию, то поиск осуществляется только в указанном каталоге. В случае неудачи возвращаемое значение равно -п.. Для получения дополнительной информации, поясняющей причину ошибки при открытии файла, к функции fopen можно обратиться с двумя выходными параметрами: [f_id err_txtI = fopen('name_file'); В случае ошибки в переменную err_txt будет занесено соответствующее сообщение. Если указанный файл обнаружен, то он открывается для чтения как двоичный файл. Второй необязательный входной аргумент функции fopen определяет режим доступа к открываемому файлу. В качестве этого параметра могут выступать один, два или три символа, заключенные в одинарные кавычки. Их назначения описаны в табл. 6.1. Таблица 6.1 Формат вызова Выполняемое действие fopen (' name_f ile *, ' г') Открывается существующий двоичный файл для чтения fopen (' name_f ile * r ' rt') Открывается существующий текстовый файл для чтения fopen (' name_f ile', ' r+') Открывается существующий двоичный файл, который можно использовать как для чтения, так и для записи (новый файл при этом не создается) fopen (' name_file', ' rt+') Открывается существующий текстовый файл, который можно использовать как для чтения, так и для записи (новый файл при этом не создается) fopen ('name_f ile', ' w ) Открывается существующий или создается новый двоичный файл для записи. Предыдущее содержимое существующего файла пропадает
210 Глава 6 Таблица 6.1 (окончание) Формат вызова Выполняемое действие f-open (' name file ', ' wt' fopen ('name_file', 'w+' fopen ('name_file', 'wt+'> fopen ('name_file', 'a') fopen('name_file' , 'at' ) fopen ('name_fiie', ' a+') fopen{'name file',,at+'} Открывается существующий или создается новый текстовый файл для записи. Предыдущее содержимое существующего файла пропадает Если существующий двоичный файл был ранее открыт, то его содержимое от текущей позиции указателя и до конца усекается. Если файл с таким именем не существовал, то создается новый файл. Открытый файл можно использовать для записи и чтения Если существующий текстовый файл был ранее открыт, то его содержимое от текущей позиции указателя и до конца усекается. Если файл с таким именем не существовал, то создается новый файл. Открытый файл можно использовать для записи и чтения Открывается существующий двоичный файл для дозаписи или создается новый файл Открывается существующий текстовый файл для дозаписи или создается новый файл Открывается существующий двоичный файл для чтения и дозаписи. Если файла с указанным именем нет, то его создают Открывается существующий текстовый файл для чтения и дозаписи. Если файла с указанным именем нет, то его создают Иногда при открытии двоичных файлов по аналогии с C++ к символам режима добавляют букву ь (от англ. binary — двоичный): гь, wb и т. д. Операции обмена как с текстовыми, так и с двоичными файлами используют указатель на начало текущей порции данных. Если файл открывают для чтения или записи, этот указатель "смотрит" на первую строку или на первый байт в соответствующем наборе данных. Если файл открывают для дозаписи, то указатель перемешается в конец данных, что позволяет присоединять новые данные в хвост к уже существующей информации. Термин усечение (trimcaie) обычно используют для операции удаления хвостовых данных, начиная от текущей позиции указателя. Поясним смысл еще одной операции, связанной с выводом в файл. В связи с тем, что скорость работы периферийных устройств, на которых располагаются внешние данные, много ниже быстродействия процессора, операции обмена используют специальные буферы, выделяемые системой. В этих бу-
Работа с файлами 211 ферах накапливается выводимая информация, которая после заполнения буфера переписывается на внешнее устройство. Когда файл закрывают, накопленная в буфере информация автоматически выталкивается в файл, чтобы не произошло потери последних данных. Это действие в англоязычной документации связывают с термином flash, flashing. Процедура открытия файлов для записи или дозаписи предоставляет программисту возможность отказаться от автоматического опустошения буферов обмена — для этой цели вместо малых букв а и w в режиме доступа следует применять их большие эквиваленты — а и w. Такие режимы на IBM-совместимых компьютерах не используются. Существуют три системных файла — стандартный ввод (stdin), стандартный вывод (stdout) и файл, предназначенный для вывода сообщений об ошибках (stderr). За этими файлами в MATLAB закреплены фиксированные номера — 0, 1 и 2 соответственно. Указанные файлы открывать не надо, они доступны всегда. В демонстрационных примерах, приводимых в данной главе, мы часто будем использовать стандартный вывод для того, чтобы наглядно представить данные, которые могли бы попасть в соответствующий файл на диске. Обращаясь к функции fopen с числовым аргументом, представляющим номер открытого файла, мы можем получить информацию о статусе этого файла (пример 6.1). ; Пример 6.1; Получение информации о статусе файла.^-¾½¾ ;Ss;^i? , .ч, \ » [паше access]=fopen{0) name = "stdin" access = x » [name access]=fopen(1) name = "stdout" access = a » [name access]=fopen(2) name = "stderr" access = a » k=fopen ('qq','wt+')
212 Глава 6 к = 3 >> [name access]=fopen(к) name = qq access = wt+ Функция f open допускает еще один формат вызова: v = fopen('all') В этом случае она возвращает вектор с номерами всех файлов, открытых к данному моменту времени (файлы с номерами 0, 1 и 2 в этот список не включаются). 6.2. Завершение работы с файлами Файл, работа с которым завершена, должен быть закрыт. Эта операция, выполняемая с помощью функции fclose, преследует две цели. Во-первых, необходимо вытолкнуть в файл вывода ту часть информации, которая накопилась в буфере обмена. Во-вторых, нужно освободить ресурсы, выделенные системой для работы с файлом. Функция fclose допускает два формата вызова: s = fclose(f_id) a = fclose{■all') В первом случае закрывается файл с указанным номером, во втором случае закрываются все открытые к этому моменту файлы. Если возвращаемое функцией значение равно -1, то операция по закрытию завершилась неудачно. Причиной тому может быть задание номера файла, который в данный момент не находится в открытом состоянии. При нормальном закрытии файла функция fclose возвращает нулевое значение. 6.3. Контроль за исчерпанием данных При выборке информации из текстового или двоичного файла, открытого для чтения, может наступить момент, когда прочитана последняя порция данных и в файле больше ничего нет. Контроль за тем, достиг ли указатель файла конца данных (end-of-Ji/e), обеспечивает функция f eof: k = feof(f id);
Работа с файлами 213 Если возвращаемое функцией значение равно о, то в файле еще находятся непрочитанные данные. При исчерпании данных значение, возвращаемое функцией feof, равно i. 6.4. Работа с двоичными файлами Указатель файла "смотрит" на текущую порцию данных. При чтении эта информация извлекается из файла, а указатель автоматически перемешается на следующую доступную порцию, если таковая еще есть. При выводе в файл новая информация записывается, начиная с адреса, на который "смотрит" указатель, а по завершению обмена указатель автоматически устанавливается на позицию, следующую за выведенной порцией. В двоичных файлах возможно дополнительное перемещение указателя по предписанию программы. Текущая позиция указателя определяется как смещение в байтах относительно начала файла. Для открытого файла с номером f_id текущее положение указателя можно узнать, обратившись к функции fteil: pos = ftell(f_id); Возврат указателя в начало файла обеспечивает функция frewind. Своим названием она обязана оператору rewind, который появился почти полстолетия назад и использовался в Fortran для перемотки магнитной ленты в начало. Единственным входным аргументом этой функции является номер открытого файла — frewind (£_id). Все остальные перемещения указателя файла реализуются с помощью функции fseek, близкий аналог которой имеется в C++. Перемещения указателя задаются относительно одной из трех позиций: □ от начала файла на заданное число байтов вперед (п>0) st = fseek(f_id,n,'bof); ИЛИ st = fseek (f_id, n,-1) ; П от конца файла на заданное число байтов назад (п>о) st = fseek{f_id, n, 'eof'); ИЛИ st = fseek(f_id,n,1); □ от текущей позиции указателя вперед (п>0) или назад (п<о) на заданное число байтов st = fseek(f id,n,'cpf');
214 Глава 6 или st = fseek(f_id,n, 0) ,- Величина смещения п может быть, в частности, равна о. Например, действие fseek(f_id, 0, 'bof') эквивалентно оператору frewind(f_id>. Нулевое значение, возвращаемое функцией fseek, свидетельствует о нормальном завершении операции. В случае ошибки возвращаемое значение равно -1. 6.4.1. Чтение данных из двоичного файла Для выборки данных из двоичного файла предназначена функция fread, допускающая несколько форматов вызова. В простейшем случае, когда ее единственным входным аргументом является номер открытого файла, функция возвращает содержимое этого файла и количество считанных байтов: [array count] = fread(f_id); При этом содержимое файла рассматривается как вектор-столбец, элементами которого являются однобайтовые числа без знака. Однако в массив array эти числа поступают уже преобразованными в формат double. Проведем несложный эксперимент. С помощью редактора m-файлов сформируем две следующие строки: ABCD 012345 Сохраним их под именем tcst.m и обратим внимание на длину получившегося файла. Несмотря на то, что мы набирали 10 символов, в файле их оказалось 12, т. к. в конце первой строки редактор вставил два управляющих символа с кодами 13 (символ CR) и 10 (символ LF). По существу, файл test.m является текстовым, но мы попробуем открыть его как двоичный файл и прочитаем его содержимое (пример 6.2). Комментарии в строках с прочитанными значениями вставлены вручную. i Пример 6.2. Чтение из текстового файла как двоичного ' ». J7_id^fopen('test.m','г'); % открываем файл как двоичный для чтения » [a k]=fread(f_id) % читаем весь файл в массив а а = % каждый элемент массива а - число типа double 65 % код буквы А 66 % код буквы Б 67 % код буквы С
Работа с файлами 215 68 % код буквы D 13 % код символа 'Возврат каретки' 10 % код символа 'Перевод строки' .48 % код цифры 0 39 .% код цифры 1 50 % код цифры 2 51 % код цифры 3 52 % код цифры 4 53 % код цифры 5. 12 % количество считанных байтов » a=char(a) % преобразование данных типа double в тип char а = % теперь каждый элемент массива а — типа char А % буква А В % буква" В С % буква С D % буква D % неотображаемый символ 'Возврат каретки' 5 неотображаемый символ 'Перевод строки' % действие управляющего символа 'Перевод строки' % цифра 0 % цифра 1 % цифра 2 % цифра 3 % цифра 4 % цифра 5 % транспонирование вектора-столбца % вывод вектора^-строки 0 1 2 3 4 5 » а' ans = ABCD 012315 Второй формат вызова функции f read использует второй входной аргумент, который задает количество считываемых символов: [array count] = fread(f_id, г.); Возвратим указатель файла test.m в начало и попробуем прочитать 8 байтов (пример 6.3). к зик кчч
216 Глава 6 К'Прймер 6.3. '^щшёз$р0Н№ » frewind(f_id) » [a k]=fread(f_id,8) a = % элементы массива а имеют тип double .65 66 .67 68 13 10 48 49 к = Количество фактически прочитанных элементов данных может не совпадать с заказанным. Обычно это случается при выборке последней порции, которая может оказаться короче предыдущих, если длина файла не кратна длинам запрашиваемых порций. Третий необязательный входной параметр в функции fread задает длину считываемых из файла компонентов вектора и их тип. Перечень допустимых значений этого параметра приведен в табл. 6.2. По умолчанию действует описатель uchar, обеспечивающий побайтный доступ к содержимому файла. Описатели другого типа рассматривают содержимое последовательно идущих двух, четырех или восьми байтов как очередной элемент вектора- столбца. В этом случае второй аргумент функции fread задает количество элементов, извлекаемых из файла. Но каждый раз очередной элемент, считанный из файла данных, преобразуется в число типа double. Таблица 6.2 Описатель длины и типа элементов Пояснение •uchar' 'schar' •intl6' 'int32' •int64' ■uintl6' 'uint8' 'int8' 1integer*2' ' integerM ' 'integer^8 ' Целое число без знака, 1 байт Целое число со знаком, 1 байт Целое число со знаком, 2 байта Целое число со знаком, 4 байта Целое число со знаком, 8 байтов Целое число без знака, 2 байта
Работа с файлами 217 Таблица 6.2 (окончание) Описатель длины и типа элементов Пояснение ' uint32' Целое число без знака, 4 байта ' uint 6 4 * Целое число без знака, 8 байтов 'single' | 'float32' Вещественное число, 4 байта ' double' | ' float 64' Вещественное число, 8 байтов Вообще говоря, MATLAB позволяет рассматривать содержимое файла как целочисленные данные с точностью до бита, если воспользоваться одним из описателей вида: П bitN — целое со знаком, длина ы битов (I < N < 64); D ubitN — целое без знака, длина N битов (1 < n < 64). Функция fread допускает наличие четвертого входного параметра, который позволяет читать данные из файла не подряд, а с заданными пропусками. Продемонстрируем эту возможность на примере того же файла test.m (пример 6.4). ■ Пример 6.4. Чтение из файла с пропусками ,'■>' -й-.,- \ ^v. ■„>£' .;■'',.¾ '-'г.^ЩШ » frewind(f_id) » [a k]=fread(f_id,20,'uchar',3) a = 65 13 .50 k = 3 Пусть вас не смущает, что мы заказали чтение 20 байтов. В файле их всего 12, и больше, чем там находится, все равно никто не прочитает. Мы по- прежнему рассматриваем содержимое файла как вектор из однобайтовых целых чисел без знака. Но после того как прочитан очередной байт, в файле пропускаются три следующих байта. Распечатка содержимого вектора а отчетливо демонстрирует режим чтения с пропусками. Режим чтения с пропусками допускает еще один вариант выборки данных из файла — сначала читается порция из п элементов, затем пропускаются m элементов, и далее все повторяется в таком же порядке. Например, чтение порциями из трех элементов с пропуском двух следующих может выглядеть так: » [a k]=fread(f id,inf,'3*uchar',2)
218 Глава 6 Так как в нашем файле содержится 12 байтов, то в массив а будет считано 6 байтов — две полные порции по 3 байта, а два последние байта не будут прочитаны (пример 6.5). » f_id=fopen( 'test.m', 'г') ,- » [a k]=fread{f_id,inf,'3*uchar', 2) a = 65 % первое число 66 % второе число 67 % третье число % два байта пропущены 10 % первое число 48 % второе число 49 % третье число % два байта пропущены 52 % первое число 53 % второе число m = 8 Массив, в который считываете*! очередной фрагмент или полное содержимое файла, не обязательно должен быть представлен одномерным вектором. Используя указание о количестве считываемых элементов из файла в виде вектора, можно сформировать результат выборки как двумерный массив (пример 6.6). Ii Пример 6.6. Чтение из файла в двумерный масёив^'гЙ'7 ч -^-^.-^¾¾¾ » f_id=fopen{'test, m', 'г'); » a=fread(f_id,[3 4]) % читаем данные из файла в двумерный массив а = 65 6.8 48 51 66 13 49 52 67 10 50 53 » whos Name Size Bytes Class a 3x4 96 double array f id 1x1 8 double array из первой порции из первой порции из первой порции из второй порции из второй порции из второй порции из третьей порции из третьей порции
Работа с файлами 219 Из приведенного примера видно, что последовательно считываемые из файла элементы данных заполняют столбцы результирующей матрицы. Если количество считываемых элементов в обращении к f read явно не указано, то данные читаются до конца файла. Точно такого же эффекта можно добиться, указав в качестве размера порции бесконечную дайну inf (или inf) — пример 6.7. I Пример6.7.Ятени"ес^ --^^-^1¾^¾¾¾^^''■'■' ^¾¾¾¾¾ » f_id=fopen('test.m', 'г') ; » a=fread(f_id,inf) a = 65 66 67 68 13 10 48 49 50 51 52 53 Такой же константой можно воспользоваться и при задании числа столбцов для матрицы-результата (пример 6.8). Шример б.а. Чтение 'файла целиком в двумерный массив V. ^^'S-*^^ |||Щ!у » 1: rewind (f_id) >> a=fread{f_id, [3,Inf]) a = 65 68 48 51 ' 66 13 49 52 67 10 50 53 До сих пор рассматривались режимы чтения файловых данных, которые могли интерпретироваться как целые или вещественные числа различной длины. Но в принимающий массив, расположенный в оперативной памяти,
220 Глава 6 они поступали уже в формате double, т. е. в большинстве случаев числовые данные подвергались преобразованию. На Это тратилось дополнительное машинное время, неэкономно использовалась оперативная память и сводились на нет заявленные выше преимущества двоичных файлов. Однако функция fread позволяет производить чтение двоичных файлов "один-води н" без какого-либо преобразования форматов или с преобразованием в числовой формат, отличный от double. Для этого в параметре, определяющем тип считываемых элементов, задается конструкция " тип1=>тип2 Левая половина этой конструкции трактуется как тип данных, находящихся в файле, а правая — как тип элементов принимающего массива (пример 6.9). Гт ■;■■- 7"T'™-?;wv3r>3v^^^^ -!Ш ;: Пример 6.9. Преобразование, формат^^ ■'fSrJ.^i:,, ■.. щ i » frewind(f_id); » a=fread(f_id,[3 4],'uchar=>uchar'j a = 65 68 48 51 66 13 49 52 67 10 50 53 » whos Name Size Bytes Class a 3x4 12 uintS array f__id 1x1 8 double array Когда тип считываемых данных совпадает с типом принимающих данных, то вместо конструкции тип1=>тип1 можно указывать более короткую строку *тип1. В приведенном выше примере можно было бы заменить uchar=>uchar на *uchar. 6.4.2. Запись в двоичный файл Операция записи в двоичный файл отличается только направлением перемещаемых данных и использует похожие аргументы с той лишь разницей, что массив — поставщик информации — теперь является входным параметром функции fwrite: count = fwrite(f_id,array,'type■); При этом в заранее открытый файл с номером fid записываются все элементы массива array с преобразованием данных в тип, определяемый
Работа с файлами 221 третьим аргументом. В качестве f_id можно использовать номера системных файлов stddut и stderr. Целочисленное значение, возвращаемое функцией fwrite, определяет количество удачно записанных элементов массива. Если значение count меньше, чем количество элементов в массиве array, то причиной тому может быть нехватка места на диске. Если массив array — двумерный, то запись его элементов в файл производится по столбцам. Проделаем несложный эксперимент (комментарий для отображаемых данных вписан вручную) — пример 6.10. ■ПрйМёр'6,10: Запись в двййчнЙЙ $айп.$^$^ *"**£Л^^€^ :?^& » al='ABCD'; % строка из четырех символов » а2='012345'; % строка из шести символов » k=fopen('abc.m','w'); % открыли двоичный файл для вывода » cl=fwrite(k,al,'uchar') % вывели в файл строку al cl = 4 $ количество записанных элементов » c2=fwrite(k,a2,'uchar') % вывели в файл строку а2 с2 = 6 % количество записанных элементов » fclose(k); % закрыли выводной файл » k=fopen('abc.m','г'); % переоткрыли файл для звода » [аЗ c3]=fread(k,inf,'*uchar') % прочитали все данные аЗ = 65 % код буквы А 66 % код буквы В 67 % код буквы С 68 % код буквы D 48 % код цифры 0 49 % код цифры 1 50 % код цифры 2 51 % код цифры 3 52 % код цифры 4 53 % код цифры 5 сЗ = 10 % количество считанных элементов » whbs
222 Глава 6 Name al a2 a3 cl c2 c3 к Size 1x4 1x6 10x1 lxl lxl lxl lxl Bytes 8 12 10 8 8 8 В Class char array char array uint8 array double array double array double .array double array Обратите внимание на то, что при записи в двоичный файл никаких дополнительных управляющих кодов типа CR, LF не пишется. Мы можем прочитать данные в их первозданном формате, если указать соответствие типов (пример 6.11). [■ Пример fcitj^HMg^ lZ$±u-&..;Atd&'^ll\--<- WU » frewind(k) » a4=fread.(k, inf, "uchar=>char') ' % чтение и транспонирование .a4 = ABCD012345 Конечно, операция по преобразованию данных из однобайтового числового представления в однобайтовый символьный формат ни с какими затратами машинного времени не связана. Но мы могли бы и при записи в файл не изменять тип передаваемых данных (пример 6.12). : Пример 6.12. Запись и чтение в двоичный файл в одинаковом 'форматё'Щййк^?^! » k=fopen ('abc.m','w'); » cl=fwrite{k,al,'char'); » c2=fwrite(k,a2,'char') ; » fclose(k); » k=fopen('abc.m','r'); >> a4=fread(k,inf,'*char')' a4 = ABCD012345 Четвертый входной аргумент функции fwrite позволяет записывать элементы указанного массива не подряд, а со вставкой перед каждым элементом заданного количества нулевых данных (пример 6.13).
Работа с файлами 223 ■» al='ABCD'; » k=fopen('abc.m','w'); » cl=fwrite(k,al,'uchar',2) % запись с разрядкой cl = 4 % количество переданных элементов массива » fclose(к); » k=fорел('abc.т','г'); » a4=fread{к,inf,'uchar') а4 = О % первый элемент разрядки О % второй элемент разрядки 65 % первый элемент массива al О О 66 % второй элемент массива al О О 67 % третий элемент массива ,al О О 68 % четвертый элемент массива al 6.5. Работа с текстовыми файлами Содержимым текстового файла являются строки — цепочки символов, завершающиеся парой управляющих кодов CR (шестнадцатеричный код od) и LF (шестнадцатеричный код or). Такие разделители строк вписывает любой текстовый редактор, когда мы завершаем набор строки нажатием клавиши <Enler>. Признак конца строки может вписать и наша программа, если формат записываемой строки (см. функцию fprintf) заканчивается управляющим кодом '\п. Для демонстрации процедур чтения строк и символов создадим с помощью текстового редактора файл text.txt, содержащий две строки: ABCD 012345 Убедитесь в том, что длина файла 12 байтов и после кода буквы "С" (шестнадцатеричный код 43) расположена пара байтов odoa.
224 Глава 6 6.5.1. Последовательное чтение строк из текстового файла Чтение очередной строки из текстового файла осуществляется с помощью функции fgetl. При этом информация из файла читается от текущей позиции указателя до тех пор, пока не встретится признак конца строки или не будут исчерпаны данные. Функция имеет единственный входной аргумент — номер открытого текстового файла — и возвращает прочитанную строку. Если данные в файле исчерпаны, а мы обращаемся к функции fgetl, то она возвращает -1 (пример 6.14). ^Пример 6.14, Последователь^ ■- .,- " . .;&ЩР/-- :i » k=fopen ('text.txt','rt'); % открываем текстовый файл » sl=fgetl(k) % читаем первую строку si = ABCD » s2=fgetl{k) % читаем вторую строку s2 = 012345 » s3=fgetl(k) % читаем несуществующие данные S3 = -1 Управляющие байты в состав считываемых строк не включаются. 6.5.2. Последовательное чтение нескольких символов из файла Один или несколько символов из текстового файла читаются с помощью функции fgets, у которой могут быть один или два входных аргумента — номер открытого текстового файла и количество считываемых символов. Чтение данных из файла начинается с текущей позиции указателя и продолжается до тех пор, пока не выполнится одно из условий: □ прочитано указанное количество символов; □ встретился признак конца строки; П данные в файле исчерпаны. Если второй аргумент не указан, то его можно считать равным бесконечности, и тогда операция будет прервана либо по исчерпанию текущей строки,
Работа с файлами 225 либо по достижению конца файла. При попытке прочитать данные после их исчерпания функция fgets возвращает -1. Приводимый пример 6.15 демонстрирует все возможные варианты. [Пример; 6i'i5vn.6ci(iMB;!tWHoe:4^ » k=fopen ('text.txt','rt'); % открываем текстовый файл » sl=fgets(k) % читаем первую строку si = ■AECD » s2=fgets{k,3) % читаем три- следующих символа s2 = 012 ~ » s3=fgets(к,5) % читаем пять следующих символов, s3 = % а в файле их осталось всего три 345 » s4=fgets(к,1) % чтение после исчерпания данных s4 = -1 6.5.3. Форматирование выводимой строки Даже в том случае, когда строка, записываемая в файл, представляет собой цепочку символов, она обязана подвергнуться преобразованию (форматированию) по двум следующим причинам: П в оперативной памяти каждый символ представлен двумя байтами, а в файле — одним; □ для того чтобы отделить одну строку от другой, вслед за последним символом на диск должна быть записана пара управляющих кодов. На самом деле символьная информация обычно перемежается с числовыми данными, которые должны быть тем или иным способом преобразованы из машинного формата в соответствующие поля строки. Таким конвертированием данных из их внутреннего представления в символьное заведуют форматные указатели, задаваемые в качестве одного из параметров функции fprintf (пример 6.16). |Л ример6. J6. Форматная запись в текстовыйфайл■■'■ '-П?~^г: -t--- .•■£.<*:■• -^1-^ » f_id=fopen('text.txt','wt'); % открыли текстовый файл » cl=fprintf(f_id,'%s\n','ABCD') % вывели в файл строку
226 Глава 6 cl = 5 » fclose(f_id); Форматные указатели всегда начинаются с символа %. В приведенном выше примере такой указатель один — %s, и он означает, что перед записью на диск необходимо преобразовать строку abcd, занимающую в оперативной памяти 8 байтов. Управляющая комбинация \п\ следующая за форматным указателем, записывается в файл как признак конца строки. Может вызвать некоторое недоумение значение, возвращаемое функцией fprintf (рис. 6.1). Рис. 6.1. Просмотр содержимого файла text.txt С одной стороны, информативных байтов записано четыре. К ним добавляется признак конца строки. Несмотря на то, что он на диске представлен двумя байтами (0D и ор.), функция fprintf рассматривает их как один управляющий элемент данных (в англоязычной документации ему соответствует символ newiine — новая строка). Первый входной аргумент функции fprintf задает номер открытого файла. Им, в частности, может быть число 1, и тогда данные передаются в файл стандартного вывода, т. е. в командное окно: » fprintf(1,'%s\n','ABCD'); ABCD To же самое происходит и при отсутствии первого аргумента: » fprintfС%s\n','ABCD'); ABCD Второй входной аргумент функции fprintf представлен строкой, содержащей форматные указатели и так называемые литеральные константы. К последним относятся все символы, не принадлежащие к форматным указателям. Литеральные константы включаются в выводимую строку без каких- либо преобразований. В частности, к литеральным константам в приводившемся выше примере относится признак конца строки. Количество указателей в строке форматов может не соответствовать количеству преобразуемых данных. И этим MATLAB кардинально отличается от других систем про-
Работа с файлами 227 граммирования. Если длина списка форматных указателей меньше, чем количество преобразуемых данных, то список циклически повторяется: » fprintfC%4d\l,2,3,4) 12 3 4 В приведенном выше примере форматный указатель %.4d повторился четыре раза. Если количество указателей, формата превышает длину выводимого списка, то лишние форматные указатели игнорируются: » fprintf('%d %f %e\l,2) I 2.000000 Данные, подлежащие преобразованию перед записью в файл, задаются третьим и последующими входными аргументами функции fprintf."Например, если мы хотим записать в очередную строку текстового файла два целых и одно вещественное значения переменных ii, i2: и гз, то это может выглядеть так, как представлено в примере 6.17. ; Пример 6f17. Преобразование данных при форматной записи - » il=125; » i2=2003; » r3=2.3456; » fprintf('%5d %d %8.3f\n',il,i2,r3>; 125 2003 2.346 Значение переменной il преобразуется в формат целого числа (об этом свидетельствует буква d в первом форматном указателе), и для его записи в выводной строке отводится 5 позиций. Между первым и вторым форматными указателями находится один пробел, который считается литеральной константой, разделяющей первое и второе число. Значение переменной ±2 преобразуется по формату %d и занимает в выводной строке 4 позиции. После второго числа вставляется еще один литеральный пробел, расположенный между вторым и третьим указателями формата. Следующие 8 позиций отведены для результата преобразования вещественного числа (об этом свидетельствует буква f в третьем форматном указателе), у которого сохраняются 3 значащие цифры в дробной части. Обратите внимание на то, что результат форматного преобразования третьего числа округлен в соответствии с общепринятыми правилами. Форматные указатели, используемые в функции fprintf, MATLAB позаимствовал у языка C++ и слегка модифицировал их. Одна из наиболее существенных модификаций, на наш взгляд, заключается в том, что элементом вы-
228 Глава 6 водного списка может быть матрица. И тогда список форматных указателей определяет преобразование каждого элемента очередного столбца матрицы. Указатель формата начинается с символа %, вслед за которым могут быть расположены три необязательные компонента — флажки, ширина (w) и точность (.п). Завершается указатель одним из символов, характеризующих тип преобразования данных и приведенных в табл. 6.3. Таблица 6.3 Символ Способ преобразования перед записью в текстовый файл формата d Преобразование целочисленного значения в десятичное число со знаком i Преобразование целочисленного значения в десятичное число со знаком о Преобразование целочисленного значения в восьмеричное число без знака и Преобразование целочисленного значения в десятичное число без знака * Преобразование целочисленного значения в шестнадцатеричное число без знака с использованием малых букв а, Ь, с,..., f в качестве цифр х Преобразование целочисленного значения в шестнадцатеричное число без знака с использованием больших букв А, в, с,..., F в качестве цифр f Преобразование числового значения в вещественное число с фиксированной запятой е Преобразование числового значения в вещественное число с плавающей запятой, признак порядка — буква е Е Преобразование числового значения в вещественное число с плавающей запятой, признак порядка — буква е g Преобразование числового значения в вещественное число с фиксированной или плавающей запятой в зависимости от того, какой формат числа занимает меньше места (незначащие нули в дробной части не выводятся) G Преобразование числового значения в вещественное число с фиксированной или плавающей запятой в зависимости от того, какой формат числа занимает меньше места (незначащие нули в дробной части не выводятся) s Преобразование текстового значения в строку символов с Преобразование единственного символа
Работа с файлами 229 В качестве флажков, следующих непосредственно после символа %, могут использоваться следующие символы: □ для вывода очередного символьного или числового значения, начиная с левой границы текущего поля (левый прижим). По умолчанию выводимое значение прижимается к правой границе текущего поля; □ + — для обязательного включения знака числа (обычно этот знак у положительных чисел опускается); П пробел — для вывода пробела вместо знака положительного числа (обычно такой пробел игнорируется); □ # — для формирования префиксов у восьмеричных и шестнадцатеричных чисел (восьмеричное число начинается с о, шестнадцатеричное — с пары символов Ох или ох). Ширина w, задаваемая целым числом, определяет количество позиций в текущем поле строки, в которых должна разместиться преобразуемая величина. Вообще говоря, ширине может предшествовать о, и тогда старшие незначащие позиции чисел заполняются не пробелами, а нулями. Продемонстрируем в примере 6.18 результат влияния флажков при заданной ширине первого и единственного поля выводимой строки (комментарии в выводимых строках проставлены вручную). » а=16; » Ь=-16; » fprintfC%5d\n%5d',a,b) 16 % число прижато к правой границе поля -16 % число прижато к правой границе поля » f print f C%+5d\n%5d',a,b) +16 % знак + у положительного числа -16 » fprintf(,%-5d\n%-5d',a/b> 16 % число прижато к левой границе поля, знак + не выводится -16 % число прижато к левой границе поля » fprintf('%- 5d\n%-5d",a,b) 16 % прижим к левой границе, пробел вместо знака +■ -16 % прижим к левой границе » fprintf (ЧЬхХпЗй.Бх'^а) ; 10 0x10 %■ префикс Ох у шестнадцатеричного числа
230 Глава 6 » fprintf (' %5X\n%#5X', a., a) ; 10 0X10 % префикс OX у шестнаццатеричного числа » fprintf{'%5o\n%#5o',a,a); 20 020 % префикс — цифра 0 у восьмеричного числа :» fprintf('%05d',a) .00016 % дополнение числа незначащими нулями Обратите внимание на то, что использование целочисленных форматов (%d, %i, %u, %х, %х, %о) предполагает, что преобразуемое значение действительно является целым (пример 6.19). ( Замечание ^ Приведенный выше текст в точности соответствует содержимому Command Window (Окно команд) среды MATLAB 6.5. Однако в среде MATLAB 7 после вывода данных по функции fprintf символы новой команды (») не переводятся в начало следующей строки. На результат вычислений и на продолжение работы это влияния не оказывает, но должного порядка на экране не наблюдается. f Пример 6.19^ИспЬльзование различных форматов веществённь1х чисел3 f" '■' i » z=1.8; » fprintf('%d',z> 1.800000e+000 % вместо формата Sd использован формат %е » fprintf('%x',z> 1.800000е+000 % вместе формата %х использован формат %е » fprijitf {' %u', z) 1.800000e+000 % вместо формата %u использован формат %е » fprintf<'%f',z) 1.80D000 % незначащие нули в дробной части выводятся » fprintfС%е',я) 1.800000е+000 % незначащие нули в дробной части выводятся » fprintf{'%Е',г) 1.800000Е+000 % незначащие нули в дробной части выводятся » fprintf('%g',z) 1.8 % незначащие нули в дробной части не выводятся
Работа с файлами 231 Если вы действительно, хотите использовать один из целочисленных форматов для преобразования вещественного значения, то перед выводом в файл такие величины нужно округлить с помощью одной из функций: fix, round, floor ИЛИ ceil. Однако MATLAB позволяет рассматривать вещественное число типа double как 8 подряд идущих байтов и записывать их содержимое в текстовый файл в виде последовательности из 16 шестнадцатеричных цифр. Для этой цели к одному из целочисленных форматов %х, %х, %о, %и добавляется символ ь (пример 6.20). г: у™ ^■^■^■■■■-"^■чгсч:.^""'"*^^^ i Пример> 6.20. Вывод вещественногочисла■«Мвста^йэте^й^цбй^дё4^^','^ » fprintf(,%bx\n%bx,,l,-l) 3ff0000000000000 bff0000000000000 Еще одну возможность подобного рода предоставляет добавление символа t к одному из указанных форматов. В этом случае вещественное значение представляется как четырехбайтовое число типа float, и оно "преобразуется" в цепочку из 8 шестнадцатеричных цифр (пример 6.21). I Пример 6.21. Вывод числа типа-^ЙгсЫГ вЧи&йн^цатё^йчнШйй^Зй";. "'—" 1 » fprintf['%.tx\n.%tx', 1,-1) 3f300000 bf800000 Естественно, что каких-либо дополнительных затрат машинного времени на такие "преобразования" не требуется. Тем не менее на некоторых вычислительных платформах после чтения данных из файла, возможно, придется менять местами старшие и младшие байты слов. Точность п, следующая за шириной и отделяемая от нее точкой, обычно определяет количество значащих цифр у вещественного числа в дробной части. Однако по правилам языка C++ точность может быть использована и в сочетании с форматными преобразованиями целых чисел, и даже строк. В первом случае преобразуемое число должно содержать в своей символьной записи не менее чем п цифр. Если их меньше, то старшие позиции числа дополняются недостающим количеством нулей. При преобразовании строки по формату %lo.5s в файл попадут не более 5 первых символов, прижатых к правой границе поля, содержащего 10 позиций.
232 Глава 6 Руководства по языку C++ содержат еще несколько менее значительных правил, определяющих влияние тех или иных сочетаний управляющих символов на способ преобразования выводимых данных. Однако они используются достаточно редко, а в случае необходимости вы можете самостоятельно заглянуть в соответствующую документацию по языку C++. (У Замечание ^ Если в списке данных, выводимых в текстовый файл, встречаются комплексные переменные или выражения, то в обработку включаются значения только вещественных частей (пример 6.22). 'Пример 6.22. Преобразование комплексных чисел при форматной записи": „ «&_ I &-файл ,¾ - у -т$ф- - г -.,¾¾■" ■ ■ ;sr: ^.. жъ ^?г*$®т?Ш \ ь;.,..£. „-.- ..:Ш, .-;..-.зг:;г.„;..,.--..,.,. :...... „:. «...й от,.ы. „<и:.;„ .....:^ ■ :. •..,.} » a=l+2*i а = 1.0000 + 2.000'0i » b=3+4*j b = 3.0000 + 4.0000i » fprintf ('%4.2f\n%4.2f, a, b) 1.00 3.00 Функция fprintf возвращает количество байтов, которое ей удалось записать в указанный файл (с учетом ранее сделанного замечания о том, что признак конца строки рассматривается как один двухбайтовый символ newiine). Обычно этим значением функции fprintf редко кто не пользуется. Единственная ситуация, в которой возвращаемое значение может помочь, связана с поиском ошибки в строке форматных указателей. Иногда MATLAB не выдает никаких сообщений, но и не выполняет запись соответствующего значения выводного списка в файл (пример 6.23). |Примёрф23г6шибкй:в-ф\>рЪ -. ; -^''.?|£^ч^ЙЙ:^ >> n=fprintf('%d %bd',1,-1) 1 n = % формат %bd не обслуживается, но и не критикуется 2 » n=fprintf (' %d %d\ 1,-1) 1 -In = 4
Работа с файлами 233 Продемонстрируем действие форматных указателей в ситуациях, когда элементом выводного списка является вектор или матрица (пример 6.24). » х=0:0.2:1 % вектор из 6 компонентов х = Q 0.2000 0.4000 0.6000 0.8000 1.0000 » fprintf('%g ',х) % вывод компонентов вектора в одной строке 0 0.2 0.4 0.6 0.8 1 » у=[х; sin(x)] % массив размерности 2x6 У = 0 0.2000 0.4000 0.6000 0.В000 1.0000 0 0.19В7 0.3894 0.5646 0.7174 0.8415 » fprintf{'%4.1f %8.4f\n',y) % вывод массива в виде 6 строк 0.0 0.0000 0.2 0.1987 0.4 0.3894 0.6 0.5646 0.8 0.7174 1.0 0.8415 Среди литеральных констанг в командной строке кроме уже упоминавшегося признака конца строки ('\п') могут использоваться и другие управляющие символы, известные под названием Esc-последователъноапи. Их перечень приведен в табл. 6.4. Таблица 6.4 Символ Описание \Ь Удаление предыдущего символа (Backspace) \£ Перевод страницы (Form feed) \п Новая строка (New line) \г Возврат каретки (Carriage return) \t Горизонтальная табуляция (Horizontal tab) Некоторые символы форматной строки задействованы как управляющие: П с символа % начинается форматный указатель; П одиночная кавычка открывает и закрывает строку форматов; П обратная косая черта использована в Esc-последовательностях.
234 Глава 6 Для того чтобы включать такие символы в состав литеральных констант и не путать их с управляющими комбинациями, в форматной строке действуют следующие соглашения: П %% — воспринимается как символ процента; □ \\ -^ воспринимается как обратная косая черта; П ' ' — воспринимается как одиночная кавычка; 0 \" — воспринимается как двойная кавычка. ( Замечание ^ В том случае, когда в текстовый файл с помощью функции fprintf записывается единственная строка, строка форматных указателей может быть опущена (пример 6.25). 1 Пример 6.25. Запись в текстовый файл без форматнь|х,указателей ' j;*''_■'-. *^''Ф| » m-fprintf ('ABCDEFGH IJKLMN1 ) ; ABCDEFGH IJKLMN » m m = 15 6.5.4. Чтение данных из текстового файла Выборка данных из текстового файла может быть произведена с помощью функции fscanf, обращение к которой в общем виде выглядит следующим образом: [a n]=fscanf(f_id,'format',т) ; Здесь: Па — принимающий массив, в элементы которого заносятся считываемые данные; П п — количество фактически считанных значений; П f_id — номер открытого файла; П format — список форматных указателей, в соответствии с которыми осуществляется преобразование считываемых данных; П m — количество запрашиваемых данных. Обязательными параметрами в этом обращении являются массив а, идентификатор файла fid и хотя бы один форматный указатель в списке format. Отсутствие количества запрашиваемых значений или константа inf в каче-
Работа с файлами 235 стве третьего параметра воспринимаются как задание прочитать данные до конца файла. Если количество запрашиваемых значений задано числом т, то считываемые данные размешаются в векторе-столбце размерности mxi. Однако, указав количество запрашиваемых данных в виде вектора [р q], мы можем прочитать данные из файла в матрицу размерности pXq. Продемонстрируем описанные возможности на следующем примере — сгенерируем магический квадрат размером 5x5, запишем его элементы как целые числа в текстовый файл a.txt, а затем попробуем разными способами прочитать эту информацию (пример 6.26). \ Пример .6.26. Запись и чтение » k=fopen{'a.txt','wt'); » a=raagic{5) a = Ле из. текстового файла -&? * ---¾.¾~" •.-:■: :\+ ~ ■' • % открыли файл лля вьшода % сформировали магический квадрат 17 23 4 10 11 24 5 6 12 18 1 7 13 19 25 8 14 20 21 2 15 16 22 3 9 » n=fprintf (к, 'Ы ' ,а) п = 66 » fclose(к); » k=fopen('a.txt', 'rt') ; » [b n]=fscanf (к,'%d\ [5 5] b = 17 23 4 10 11 24 5 6 12 18 1 7 13 19 25 8 14 20 21 2 % записали массив а в файл % количество Сайтов, записанных в файл % закрыли файл % открыли файл для чтения ) % читаем матрицу 5x5 15 16 22 3 9 25 » f rewind Ik) ; » [с n]=fscanf (k, '%d.\5) с = 17 23 %■ количество считанных значений % вернули указатель файла в начало % прочитали 5 значений (1-й столбец)
236 Глава 6 10 11 5 » whos Name a b с к n Size 5x5 5x5 5x1 lxl lxl Bytes 200 200 40 В 8 Class double double double double double array array array array array Обратите внимание на разницу в возвращаемых количествах между функциями fprintf и fscanf. Первая из них считает количество байтов, записываемых в файл, а вторая возвращает количество элементов данных, считанных из файла. При выводе в файл кроме указателя %d в форматной строке присутствует пробел, разделяющий числовые данные. Если вы посчитаете количество цифр в элементах магического квадрата и добавите к ним 25 пробелов (по одному пробелу после каждого числа), то получится 66 байтов. Форматные указатели, задаваемые в строке формата у функции fscanf, почти те же, что и у функции fprintf (см. табл. 6.3). Но если точность при выводе имеет определенный смысл, то на ввод она не оказывает влияние. При считывании вещественных данных из текстового файла указатели типа %f, %е и %д выполняют одинаковые функции, преобразуя считанное значение в машинный формат типа double. Форматные указатели типа %d, %i выбирают из очередного поля текстового файла целочисленные данные, однако в элементы принимающего массива результат преобразования заносится в формате double. Если форматный указатель начинается с комбинации %*, то соответствующее значение, считанное из файла, в принимающий массив не передается. Это дает возможность пропускать ненужные данные. В примере 6.27 показано считывание данных из файла с магическим квадратом и пропуском каждого второго числа. •, Пример 6.27<;Чтение И3 текстового файла с пропусками - *■- "{•- ■ ,-.:' » frewind(k); » [d n]=fscanf(k,'%d %*d')
Работа с файлами 237 d = 17 4 11 5 12 1 13 25 14 21 15 22 9 г. = 13 Форматные указатели типа %s на выводе и на вводе действуют по-разному. Строка данных, записываемая в файл, например, может содержать пробелы. Однако если мы читаем единичный элемент по формату %s, то чтение прерывается на первом же пробеле. Если мы запрашиваем чтение более чем одного элемента, то белые пробелы, встречающиеся в текстовой строке, игнорируются (пример 6.28). |;Пр;Имёр.&2в,:рбра!5а1^про^ » k=fopen ('a.txt','wt'); » fprintf(k,"%s','ABCD 012345') % записали строку с пробелом ans = 11 % количество записанных байтов » tclose(k); » k=fopen ('a.txt','rt'); » [a n]=fscanf(k,'%s',l) % прочитали 1 элемент до первого пробела а = ABCD п = 1 » frewind(к)у » [a n]=fscanf(k,'%s',2) % прочитали 2 .элемента
238 Глава 6 а — ABCD012345 % пробел проигнорирован п = 2 » k=fopen('a.txt','wt'); * открыли файл » fprintf (k,'%s\n%s','ABCD','0123.45'); % записали 2 строки >> fclose(k); » k=fopen ('a.ty±','rt'); » [a nj=fscanf(k,'%s') % читаем все данные a - ABCD012345 % признак конца 1-й строки проигнорирован л = 2 %. прочитаны 2 элемента " 6.6. Форматные преобразования в оперативной памяти Все, что выше было сказано о работе функций fprinf и fscanf, можно повторить для функций sprintf и sscanf. Если в первом случае в качестве сторон, обменивающихся информацией, выступали массив, расположенный в оперативной памяти, и файл, находящийся на диске, то во втором случае вместо файла выступает строка, расположенная, как и массив, в оперативной памяти: [str errtxt] = sprintf('format',al,a2,...); % запись в строку str [a n] = sscanf(str,'format',m); % чтение из строки str Достаточно подробно работа этих функций рассматривалась в разд. 5.7. 6.7. Анализ ошибок в файловых операциях Обмен с файлом может завершиться ошибкой. Получить соответствующее сообщение и узнать номер ошибки поможет функция ferror: msg_ecr = (Terror (f_ict) ; |msg_err num_err] = ferror(f_id); Если последняя операция обмена с указанным файлом завершилась нормально, то в символьную переменную msgerr записывается пустая строка, а в качестве номера ошибки в переменную num_err заносится о. Если же
Работа с файлами 239 обнаружена нештатная ситуация, то числовой код ошибки будет отличен от о. Для продолжения работы с данным файлом необходимо сбросить признак аварийной ситуации: [msg_err num__err] = ferror(f_id, 'clear1); 6.8. Альтернативный доступ к текстовым файлам Функция textread (пример 6.29), которая позволяет читать данные из текстового файла, отличается от функции fscanf в первую очередь тем, что файл не нужно открывать. Обращение к файлу производится не по номеру открытого заранее файла, а по его имени. Конечно, такой способ менее удобен, т. к. переключение на другой файл данных связано с внесением большего количества исправлений. Вторая особенность функции textread заключается в том, что при чтении из текстового файла, заполненного только числовой информацией, можно не задавать строку форматных преобразований. Наконец, функция textread обладает большей гибкостью, т. к. с помощью дополнительной пары аргументов типа "параметр — значение" позволяет пропускать строки комментариев, управлять выбором символов-разделителей, регулировать размеры буфера обмена и др. В простейшем случае у функции textread может быть задан единственный аргумент. г.,.....г..„..,у,Ы„.---у-:;,ъ\^^^^^^^ ,„,,..,„,...,...,..,... ,.......; I Пример, 6.29. Чтение из текстового файла с по^ taxtread » K=fopen('a.txt','wt'); % открыли текстовый файл » fprintf(k,'%d ',1,2,3,4,5); % записали 5 чисел » f close (k) ; » a=textread('a.txt') a = 1. 2 3 4 5 ( Замечание ) В среде MATLAB 7 этот пример выполняется неправильно — вслед за пятым числом извлекается несуществующий 0. Скорее всего это ошибка системы. Для того чтобы читать не все данные, среди входных аргументов должны находиться форматная строка и количество запрашиваемых чисел (пример 6.30).
240 Глава 6 i Пример 6.30. Формйтнр? чтение из текстового фаила.с помощью функции . ■ \ ;■ i.ii;.........-...-.-.-.'. 1...V..1. .C;.^v:i..:;.^..v;rh;-.^V..-.:..:..rt^^^ ..Ы............. -.н » b=textread(,a.txt',' %d\2) b = 1 2 Если задан формат, но не указано количество запрашиваемых чисел, то из файла извлекаются все данные (пример 6.31). h Пример;6.31 ДФорматйое .чтение' тёКртовр}ф\файла> целиком fe^fW**41 » b=textread('a.txt','%d'> b = 1 2 3 4 5 Данные можно прочитать не только в массив, но и разбросать их по отдельным переменным, но при этом каждой выходной переменной должен соответствовать свой форматный указатель (пример 6.32). ^Примере. . ч" текрт вогоЛаедСв-л^^ » [bl Ь2 b3 b4 bSHtextreadCa.txt','%d %d. %d %d %d') bl = 1 b2 = 2 ЪЗ = 3 b4 = 4 b5 = 5
Работа с файлами 241 Приписав символ * к любому из перечисленных выше форматных указателей, мы можем пропустить соответствующее числовое значение (пример 6.33). » [Ы ЬЗ b5]=textread('a.txt','%d %*d %d %*d %d'> Ы = 1 ЬЗ = 3 Ь5 = 5. Форматная строка может быть пуста, но при этом из текстового файла можно прочитать только числовые данные (пример 6.34). : Пример 6,34.: Нтёнйёйэ текстового файла с пустой форматной строкой ^,¾¾ :.4¾ » b=textread('a.txt', " ) b = 12 3 4 5 ( Замечание ) В среде MATLAB 7 этот пример выполняется неправильно — вслед за пятым числом извлекается несуществующий 0. Скорее всего это ошибка системы. Форматные указатели, используемые в функции textread, немного отличаются от тех, которые приводились в табл. 6.3. Их специфика отражена в табл. 6.5. Таблица 6.5 Формат Выполняемое преобразование ■%п Целое или вещественное число преобразуется из символьного формата в формат double %d Целое число со знаком преобразуется из символьного формата в формат double %u Целое число без знака преобразуется из символьного формата в формат double %f Вещественное число преобразуется из символьного формата в формат double
242 Глава 6 Таблица 6.5 (окончание) Формат Выполняемое преобразование %s Строка, завершающаяся белым пробелом, преобразуется в элемент массива ячеек %q Строка, возможно, заключенная в двойные кавычки, преобразуется в элемент массива ячеек %с Символ или белый пробел преобразуется в символьный массив % [sls2... ] Строка из символов, входящих в заданный набор, преобразуется в элемент массива ячеек. Чтение прерывается при выборе символа, не входящего в заданный набор % (Лз1з2 . . . ] Строка из символов, не входящих в заданный набор, преобразуется в элемент массива ячеек. Чтение прерывается при выборе символа, входящего в заданный набор В форматных указателях после символа % может быть задано целое число, ограничивающее количество преобразуемых символов текстового файла, если до этого не будет обнаружен настоящий символ-разделитель. В качестве символа-разделителя по умолчанию используется белый пробел. В качестве последних параметров функции textread могут задаваться пары типа "свойство — значение", имеющие целью по желанию пользователя подменить тот или иной управляющий символ или изменить значение какой-либо системной характеристики. Возможные сочетания таких пар приведены в табл. 6.6. Таблица 6.6 Свойство Пояснение, возможные значения 'buf size' Максимальная длина строки в байтах (по умолчанию — 4096) 'commentstyle' Комментарий при выборке из текстового файла можно проигнорировать. Допустимые значения свойства: • 'mat lab': начало комментария в гл-файлах — символ %; • 'shell': начало комментария — символ #; • 'с': комментарий в С-программах—/* комментарий "'/; • 'с++': начало комментария в программах на C++ — символ / / 'delimiter' Символ-разделитель элементов в считываемой строке 'emptyvalue' Способ передачи пропущенного значения 'endofline' Признак конца строки
Работа с файлами 243 Таблица 6.6 (окончание) Свойство Пояснение, возможные значения 'expchars' Символ десятичного порядка (по умолчанию — еЕсЮ') 'headerlines' Количество пропускаемых строк в заголовке файла 'whitespace' Белые пробелы (по умолчанию — '\b\t') В файлах помощи по функции textread приводится несколько полезных примеров, иллюстрирующих особенности выборки данных из текстового файла и использования дополнительных параметров "свойство — значение". Прокомментируем эти слегка модифицированные примеры. Пусть в текстовом файле с именем datal.dat должны находиться три строки- записи, содержащие по пять полей со следующей информацией: Sally Typel 12.34 45 Yes Joe Type2 23.54 60 No Bill Typel 34.90 12 No Сформируем эти значения с помощью функции fprintf (пример 6.35). ; Пример Q.35. Формирование текстового файла • - » k=fopen ('da tal.dat', 'wt'); » fprintf {k,'%s\n\'Sally Typel 12.34 45 Yes'); » fprintf(k,'%s\n','Joe Type2 23.54 60 No'); » fprintf(k,'%s\n','Bill Typel 34.90 12 No'); » fclose (k) ; А теперь попробуем извлечь информацию из этих полей в соответствующие массивы. Разделителями данных в нашем случае являются белые пробелы, в число которых входят настоящие пробелы между значениями полей и символы перехода на новую строку. Как только список форматных указателей исчерпывается, он повторяется заново, а считываемые данные пополняют следующие элементы наших массивов: » [names,types,х,у,answer5 = textread('datal.dat','%s%s.%f%d%s') names — 'Sally' 'Joe' •Bill' types == 'Typel'
244 Глава 6 'Туре2' ■Typel' х = 12.3400 23.5400 34.9000 У = 45 60 12 answer" = 'Yes' 'No' 'No' » whos. Name answer names types X У Size 3x1 3x1 3x1 3x1 3x1 Bytes 194 204 210 24 24 Class cell array cell array cell array double array double array Обратите внимание на то, что содержимое символьных полей, считываемых по формату %s, поступает в массивы ячеек, а содержимое числовых полей — В МаССИВЫ ТИПа double. Теперь попробуем прочитать из содержимого того же файла только значения первого поля, пропуская все остальные данные каждой строки до признака newline (пример 6.36). =. .Пример-6,3!Б:-ВыбррОчНр^ » [names]=textreadСdatal.dat','%5%*[Л\п]') names = 'Sally' 'Joe' 'Bill' Конечно, процедуру пропуска значений четырех оставшихся полей можно было бы оформить и с помощью следующей строки форматных указателей — %s%*s%*f%M%*s. Однако здесь продемонстрирован сравнительно редко ис-
Работа с файлами 245 пользуемый формат, который в данном примере звучит как "пропускать все символы кроме символа newiine ('\п')"- Обратите внимание на то, что форматный указатель %s пропускает все белые пробелы, в т. ч. и символы перехода на новую строку. Заменим в предыдущем примере формат %s на указатель %с (пример 6.37). !гПример 6.37. Выборочное чтение символов из текстового файла 1^(¾¾¾¾¾¾¾¾ » [names]=textread('datal.dat','%c%*["\n]') names = Б J В » whos Name Size Bytes Class names 3x1 6 char array После выборки первого символа строки ее остаток был проигнорирован до появления символа newiine, затем список форматов повторился и из следующей строки был извлечен еще один символ. И все это повторилось еще один раз (пример 6.38). В отличие от формата %s, по которому результаты преобразования имели тип cell array, результат преобразования по формату %с Имеет ТИП char array. | Пример 6.38. Выборочное чтение из файла в переменные равных типов; ^ф0^;\ » [names,-type's,у, answer] = textread( 'datal .dat', '%9c%5s%*f%2d%3s') names = Sally Joe Bill types = 'Typel' •TypeZ" 'Typel' У = 45 60 12
246 Глава 6 answer = 'Yes' 'Ко' 'No' » whos Name answer names types У Siz« 3x1 3x9 3x1 3x1 Bytes Class 194 cell array 54 char array 210 cell array 24 double array Интересен результат преобразования при чтении данных по формату, представленному в примере 6.39. [Пример 6.39. Чтение(Текстового феШа'по заданному формату ■ » [names,typenum,x,у,answer]=textread('datal.dat','%sType%d%f%d%s') names = •Sally' 'Joe' 'Bill' typ.eiium = 1 2 1 x = 12.3400 23.5400 34.9000 У = 45 60 12 answer' = •Yes' 'No' 'No'
Работа с файлами 247 whos Name answer names typenum X У Size 3x1 3x1 3x1 3x1 3x1 tes 194 204 24 24 24 Class cell array cell array double array double array double array Включение литеральной константы туре в список форматных указателей привело к тому, что аналогичные символы из считываемой строки были извлечены в воздух. Зато следующий за ними символ был воспринят как целое число и результат его преобразования по указателю %d был сохранен в элементах вектора typenum В формате double. Содержимое текстового файла в естественном виде по строкам можно прочитать так, как показано в примере 6.40. ■текстового гЬайла' УУ^Щ..ff^-^AW «В*-4?^ ?- Пример 6.40. Построчное чтение текстового файла » file = textreadCdatal.dat','%s','delimiter','\n','whitespace','') file = Typel 12.34 45 Yes' Type2 23.54 60 No' Typel 34.90 12 No' 1 Sally 'Joe 'Bill » whos "Name file Size Bytes Class 3x1 338 cell array Без подмены стандартных разделителей и белых пробелов результат чтения был бы совершенно другим (пример 6.41). | Пример 6.41, Ошибки при отсутствии обработки разделителей « - '""■■<■ -■;' .. » file = textreadCdatal.dat', '%s') file = 'Sally' 'Typel' 42.34' '45' 'Yes' 'Joe' « Зак. 899
248 Глава 6 'Туре2' '23.54' '60' •No" •Bill' •Typel' '34.90' 42' 'No' » whos Name Size Bytes Class file 15x1 1010 cell array При чтении числовых данных, разделенных запятыми, среди которых могут оказаться "пустые" поля (две подряд идущие запятые), можно воспользоваться свойствами delimiter и emptyvalue. Сформируем в текстовом файле с именем data2.dat следующие строки: 1,2,3,4 5,6,7,8 9,10,11,12 При чтении по пустой форматной строке числа, разделенные запятыми, заполняют строку результирующей матрицы. Но как только встречается символ newiine, происходит переход к следующей строке результирующей матрицы (пример 6.42). | Дример^^ЧтМ^ » data = textreadCdata2.dat', ",'delimiter',',') data = 12 3 4 5 6 7 8 9 10 11 12 Однако стоит нам задать какой-либо форматный указатель, как возвращаемые значения заполняют вектор-столбец (пример 6.43). ^Пример 6.43, ЧтенКедекстовых данных, с разделителем; g;-: *-\*-ж *■?■*w*«5u -^- » [data]=textread('data2.dat','%n','delimiter', ', ') data = 1
Работа с файлами 249 2 3 4 5 6 7 8 9 10 11 12 Варьируя количество выходных аргументов и пропуская часть строки, можно, например, прочитать только два первых столбца матрицы, хранящейся в текстовом файле (пример 6.44). I Призер 6.44.4}фнй£р;ад(»л"^ к. ,; ■ j » [coll, со12] = textreadfdata2.dat','%n%n%*[Л\п]','delimiter',',') coll = 1 5 9 col2 = 2 6 10 Сформируем третий текстовый файл с именем data3.dat, в котором заданы некоторые пустые поля: 1,,3,4 5,6,,8 9,10,11,, Воспользуемся свойством emptyvalue, которое позволяет заменить отсутствующие данные указанным значением (пример 6.45). = Пример 6.45. Чтенй^текстового файла С^стыми^РШМи^^^^^^^ i -...:.-..-...:.. .-..;..л.-.'.-.:.:.. ?... ;-.^...:.л...:;:.-:;..-:'.::..'.':.-. ;:::7.::..\.ъ;-.:.:*л.-::к:.л.-^ » data = textread('data3.dat','','delimiter',',','emptyvalue',KaN) data = 1 NaN 3 4
250 Глава 6 5 6 NaN 6 9 10 11 NaN ( Замечание ^ В среде MATLAB 7 этот пример выполняется неправильно — в результате появляется лишний пятый столбец, содержащий только элементы ЫаЫ. Мы сохранили правильную выдачу, полученную в среде MATLAB 6.5. Скорее всего это ошибка системы. Обратите внимание на пропущенное значение в третьей строке файла data3.dat — оно расположено между двумя запятыми. Между ними может быть несколько пробелов, которые не оказывают никакого влияния на результат преобразования. Но стоит нам удалить последнюю запятую, как изменяется результат преобразования последнего элемента матрицы (пример 6.46). Шример 6Д6л;Р|щй6оч>1>8;тра«сг9вка последнего данного-„ :Щ^^ШШЖ ГЛШ 1,,3,4 5,6,,8 9,10,11, » data = textread('data3.dat','','delimiter',',','emptyvalue', NaN) data = 1 NaN 3 4 5 6 NaN R ■9 10 11 0 ( Замечание ^ В среде MATLAB 7 и этот пример выполняется неправильно — вместо последнего нулевого элемента появляется NaN. Скорее всего это ошибка системы. 6.9. Числовые файлы с разделителями MATLAB предлагает еще одну разновидность текстовых файлов, содержащих последовательность чисел, отделяемых друг от друга символами- разделителями. Создаются такие файлы с помощью функции dimwrite: dlmwrite (' f ile_name', a., dim) ; В этом случае создается файл с именем filename, и в него записываются элементы числового массива в символьном представлении. Вслед за каждым числовым значением в файл записывается символ dim. Если записываемый
Работа с файлами 251 массив двумерный, то его элементы выводятся в файл по строкам (пример 6.47). \ Пример 6.47. Запись в числовой файл с р.аддвлйтепями:.^/^Ш^^ЙШ^4^^%^ I .....:..:.....:......... ...:v.*...-.'..i;;v.,.:,...',.:. .;;;:..■ ■...л".:...*;.:;.-..;.;;.;;*..^^";^^ .; » a = magic(4) а = 16 2 3 13 5 11 10 8 9 7 6 12 4 14 15 1 » dLmwrite('dim.txt', а, ';') Замечание Данные в dim-файл записываются только один раз. Любая последующая запись в файл с тем же именем уничтожает предыдущие данные. Из созданного таким образом текстового файла, строки которого завершаются символом LF (шестналцатеричный код оа), числовые данные читаются с помощью функции dimread (пример 6.48), допускающей три формата обращения: b = dimread('file_name', dim); b = dimread('file_read', dim, n,m); b = dimread('file_naree',dlm, [nl ml n2 m2]); В первом варианте из файла считываются все числовые данные, каждая строка которых образует строку в выходном массиве. Во втором случае из файла читается только фрагмент расположенной там матрицы. Левый верхний угол этого фрагмента задается номером строки п и номером столбца m (отсчет индексов ведется от о, а не от 1, как это принято во всех матричных операциях MATLAB). В третьем формате вызова задается не только верхний левый угол фрагмента, но и индексы правого нижнего угла. г Пример 6.48; Чтение, из числового файла ср^зделитея^ми;ш«гЛй^^кК&»м^ » b=dlmread('dim.txt',';') b = 16 2 3 13 5 11 10 8 9 7 6 12 4 14 15 1
2S2 Глава 6 » c=dlmread(■dim.txt',';',2,1) с = 7 б 12 14 15 1 » d=dlmread('dlm.txt\';',[0 1 2 3]) d = 2 3 13 11 10 8 7 6 12 При записи массива в файл с помощью функции dimwrite тоже имеется возможность задания двух дополнительных индексов. Но речь идет не о выводе части массива, а о месте расположения записываемых данных в файле (пример 6.49). » dimwrite{'dim.txt', a,';',2,1) » d=dlmread('dim.txt■,';') d = 0 0 16 5 9 4 0 0 2 11 7 14 0 0 3 10 6 15 0 0 13 '8 12 1 Попытка задать отрицательные дополнительные индексы не расценивается как ошибка, но они автоматически заменяются нулевыми значениями (пример 6.50). : Пример 6,50, реакция системьгна"ошие!0нно^,задан^9йсум]е,нто8 fee ^. v г % щ » dimwriteС dim. txt",a,',',-2,-1) » b=dlmread( 'dlm.txf,', *) b- = 16 2 3 13 5 11 10 8 9 7 6 12 4 14 15 1
Работа с файлами 253 А для того; чтобы записать часть массива, можно воспользоваться обычным для MATLAB способом выделения нужного фрагмента (пример 6.51). Не забывайте только, что в этом случае граничные значения индексов ведут отсчет от 1. • Пример6.51/Записьнаети'массивавчисловоифаил ^#^Зп&*#дЗД^ ч-&<£ » dlmwriteCdlm.txt'jafaM,2:3) , \ ') » b=dlmread('dim.txt',',') b = 11 10 7 6 14 15 Если в dim-файл записываются вектор-строка или вектор-столбец, то числовые данные в файле имеют такую же организацию, как и исходные данные (пример 6.52). пример 6.52. еохранен|йеррганиза]цИ » а=[1 2 3 4 5 6]; » dlmwrite('dlm.txt', а, ', ') » b=dlmread(■dim.txt',',') b = 12 3 4 5 6 » c=[l;2;3;4;5;6]; » dlmwrite('dlm.txt',c,',') » d=dlmread('dim.txt',',') d = 1 2 3 .4 5 6
Глава 7 Иерархия графических объектов и их свойства Для более точного понимания материала настоящей главы нам потребуются некоторые термины, присущие объектно-ориентированному подходу (ООП) в современных системах программирования. Понятие класс обычно связывают с некоторым шаблоном, по образцу и подобию которого строятся объекты — фрагменты программы, объединяющие в себе данные и функции обработки этих данных. Объявление класса эквивалентно объявлению структуры данных и описанию методов (функций) их обработки. Когда создаются несколько объектов, порожденных данным классом, то каждый объект получает личную оперативную память для хранения своих данных. А функции их обработки при этом не дублируются. Набор методов класса обслуживает данные любого объекта этого же класса подобно тому, как стандартные функции получают разные аргументы и для каждого из них выдают соответствующие результаты. Данные в каждом объекте, порожденном одним и тем же классом, имеют одинаковые имена и, чтобы различать, с какими аргументами должен проработать вызываемый метод, он должен получить не только набор соответствующих параметров, но и узнать, какой объект должен быть обслужен. В большинстве универсальных алгоритмических языков вызов методов класса по форме отличается от вызова обычных подпрограмм и функций (табл. 7.1). Таблица 7.1 Язык Вызов Вызов метода Пояснение программи- функции рования VisualBasic z = f(x,y> г = Obj.F(a,b) obj — имя объекта pOb j — указатель на объект F — имя метода
256 Глава 7 Таблица 7.1 (окончание) Язык программирования C++ Builder Delphi Вызов функции z = f(х,у); z := fix,у) Вызов метода z = pObj->F[a,b); z = Obj.F(a,b); z := Obj.F(a,b); Пояснение Может показаться, что объектно-ориентированный подход существенно усложняет жизнь программиста. Однако первое впечатление обманчиво. Поясним это на простом примере. Пусть существует несколько классов, каждый из которых связан соответственно с обработкой точек, отрезков прямых и окружностей. Предположим, в каждом классе определен свой метод отображения соответствующей графической фигуры на экране дисплея. А называются эти методы, представленные, естественно, разными программами, все одинаково — show. Насколько прозрачнее выглядит обращение к отображению точки рцх.у), отрезка ы (xl,yi,x2,y2j и окружности oi(xO,yO,R) по сравнению с традиционными вызовами соответствующих функций: putpixel(х, у); PI. Show; line(xl,yl,x2,y2); Ll.Show; circle <х0,уО,R); 01. Show; На самом деле, сообщая методу имя объекта, мы неявно передаем и сведения об этом объекте, которые хранятся в соответствующих информационных полях. Класс позволяет защитить нужные данные от внешнего воздействия, проконтролировать правильность их задания, поскольку к определенной информации доступ возможен только через методы типа set (установить новое значение) и get (опросить текущее значение). Такой подход, несмотря на дополнительные накладные расходы, позволяет предотвращать многие ошибки и разрабатывать достаточно хорошо защищенные программы. Для создания объекта с именем nam_obji, построенного в соответствии с шаблоном класса nam_cis, в языке C++ прибегают к специальным функциям — конструкторам, имена которых совпадают с именем класса: nam_cls nam__obj 1; nam_cls nam_obj1(al,a2); nam_cls nam__objl (nam_obj2) ; В первом случае конструктор создает объект, присваивая каким-то его данным значения по умолчанию, предусмотренные шаблоном класса. Во втором
Иерархия графических объектов и их свойства 257 случае конструктору передаются параметры (al,a2), которые используются для начальной инициализации некоторых данных объекта. В третьем случае вновь создаваемый объект получает начальные значения, которые были использованы при создании уже существующего объекта nam_obj2. Конструкторы обладают двумя полезными свойствами. Во-первых, они могут проконтролировать правильность выделения ресурсов (в первую очередь, оперативной памяти), необходимых для нормального функционирования объекта. Во- вторых, они не допустят инициализации параметров объекта непредусмотренными значениями. Именно поэтому прямой доступ к жизненно важным данным объекта запрещен, и для установки новых значений или опроса текущих значений обычно прибегают к функциям-посредникам, которые в состоянии проконтролировать правильность той или иной операции. Еще одна важная процедура, называемая деструктором, используется в ООП для автоматического уничтожения объекта после выхода из блока программы, в которой объект был объявлен. Деструкторы создаются и, как правило, вызываются автоматически, освобождая программиста от заботы по возврату занятых ресурсов. В C++ имена деструкторов тоже совпадают с именем класса, однако им предшествует символ ~ (-nam_cis). Еще один термин, который появился немного позже и активно используется в системах визуального программирования, представляет наиболее характерные свойства объекта (properties по терминологии C++). Большинство из них определяет внешний вид объекта и/или управляет его функционированием во время выполнения программы. К свойствам, присущим многим объектам, относятся их габариты (ширина, высота), местоположение на экране или внутри некоторой области, цвет, характеристики используемого шрифта (имя шрифта, высота символов, наклон, утолщение контура, подчеркивания), видимость объекта, его активность или пассивность и др. Некоторые из таких свойств могут изменяться на стадии проектирования программы, и пользователь способен визуально оценить принимаемые им решения. Другие свойства оказываются доступными только на стадии выполнения программы, причем некоторые из них можно только опросить (доступны только для чтения). Для работы со свойствами объектов, в универсальных системах программирования используются составные имена: Labell->Caption="CKopocTb"; //так это выглядит в C++ Label1.Caption:='Скорость'; (так это выглядит в Delphi) В приведенном примере свойству Caption (заголовок) объекта с именем Labeli (метка) присваивается указанное символьное значение. Объектно-ориентированное программирование никогда бы не состоялось, если бы в нем не была предусмотрена процедура порождения новых классов из уже существующих с наследованием данных, методов и разграничением способа доступа к ним. На основе существующего класса а (базовый класс) мы можем определить класс в (производный класс), который получит в на-
258 Глава 7 следство все или часть методов и данных базового класса. Производный класс способен переопределить часть методов, доставшихся по наследству, добавить новые данные и методы. Класс в может, в свою очередь, стать "родителем" для следующего класса с, и таким образом легко построить генеалогическое дерево некоторой программной системы. Язык C++ допускает порождение нового класса из двух или более базовых классов (множественное наследование). Для разграничения прав доступа к методам и данным в ООП введены такие понятия, как общедоступные (public), защищенные (protected) и личные (private) компоненты. К первой категории данных и методов могут обращаться любые внешние функции. Данные и методы второй категории могут быть переданы по наследству производному классу, но от других внешних функций они защищены. Наконец, личные данные доступны только в том классе, где они определены. В системах визуального программирования появился еще один тип данных, которые можно было бы назвать сверхдоступпыми (published). Он относится к свойствам объекта, которые можно изменять на стадии конструирования программы. Изложенные выше соображения были приведены только для того, чтобы подчеркнуть разницу между общепринятой терминологией и подходами к реализации идей объектно-ориентированного программирования и воплощением близких по содержанию, но все-таки иных по форме понятий в системе MATLAB. Возможно, что причина расхождений лежит в истории создания системы, которая сначала была реализована на Fortran — языке, в котором до поры до времени никакого намека на объектно-ориентированный подход и не было. Тем не менее термины класс и иерархия классов, наследование и переопределение функций, объекты и их свойства, события и реакция на них лежат в основе таких разделов MATLAB, как структуры данных, графика и организация диалогового взаимодействия с пользователем. На рис. 7.1 приведена схема классов, отражающая структуру и иерархию компонентов графического интерфейса пользователя (Graphic User Interface, GUI). Сразу же договоримся о переводе термина handle, лежащего в основе всех манипуляций с объектами. В системе MATLAB им пользуются для идентификации различных объектов — открываемых файлов, графических окон, координатных осей, линий графика, источников света, текстовых меток, компонентов диалогового взаимодействия (кнопки, меню, окна ввода/ вывода). Значение того или иного handle можно отобразить как число, но его величина для пользователя никакого смысла не несет. Исключение составляет handle единственного объекта, порожденного классом Root. Его значение равно о, и именно его приходится указывать при опросе или установке каких-либо свойств данного объекта. Во всех остальных случаях роль
Иерархия графических объектов и их свойства 259 handle станет выполнять какая-либо переменная, значение которой будет присвоено функцией, создающей тот или иной объект. В дальнейшем мы будем называть этот системный идентификатор указателем или ссылкой на объект. Root Figure Axes Uicontrol Uimenu Button Group Uicontextmenu Panel Image Line Light Rectangle Patch Text Surface Рис. 7.1. Иерархия классов GUI В каждый конкретный момент выполнения программы выделяют три объекта — активное окно (текущая фигура), только что созданный или активизированный графический объект (текущий объект) и текущий график, владельцем которого считаются координатные оси. Независимо от способа создания этих объектов можно обратиться к одной из системных функций: gcf (от англ. get handle of the current figure), geo (от англ. get handle of the current object) и gca (от англ. get handle of the current axes) для получения значения соответствующего указателя. Полученным значением можно пользоваться при обращении к тому или иному методу обработки текущего окна, объекта или графика. Любой графический объект обладает определенным набором свойств, каждое из которых имеет индивидуальное имя. Для опроса текущего или установки нового значения того или иного свойства предназначены функции get И set: v = get (h, ' Свойство') set(h,'Свойство',Новое_значение) Первая из них возвращает значение указанного свойства, которым обладает графический объект с указателем h. Вторая изменяет текущее значение ука-
260 Глава 7 занного свойства. Обе функции допускают различные варианты обращения. В качестве первого аргумента может выступать массив указателей, и тогда соответствующая операция распространяется на группу объектов. Результат, возвращаемый функцией get, в этом случае представлен массивом ячеек, длина которого совпадает с длиной вектора h. В каждую ячейку результата заносится значение указанного свойства для соответствующего объекта. Аргумент 'свойство' тоже может быть представлен не только скалярным значением, но и массивом ячеек, значение каждой из которых определяет имя соответствующего свойства. К функции get можно обратиться и с единственным аргументом — get(h). В этом случае она возвращает значения всех свойств указанного объекта в виде пар имя = значение Количество таких свойств довольно велико, так, например, у объекта типа Axes их порядка 100. И большинством из них пользователь так или иначе может управлять. Поэтому важно знать, как влияет то или иное свойство на поведение соответствующего объекта. Функция set тоже допускает различные варианты обращения, основная идея которых заключается в задании множества пар "имя — значение": set(h,'Свойство^!.',3начение_1,*Свойство_2',Значение_2,...) set(h,struct) set(h,cell_name,cell_value) В первом случае имена свойств и соответствующие им значения перечисляются в виде списка переменной длины. Во втором случае аналогичные пары задаются как значения нолей структуры struct. В третьем случае группа имен задается ячейками массива ceii_name, а соответствующий им набор значений — ячейками массива ceii_value. 7.1. Объект Root Корнем генеалогического дерева является класс Root, символизирующий экран дисплея. Единственным объектом этого класса выступает наше приложение, которое система создает автоматически. Полный перечень его свойств и набор соответствующих им значений можно получить, обратившись к функции get с нулевым указателем (пример 7.1). ^Пример 7.1, Своие^рэ объекта Roofc -,-*&?\т^*<£^Щх*ШШ$£-. :¾¾¾¾^¾¾ j » get(O) CallbackObject = []
Иерархия графических объектов и их свойства 261 CoinmandWindowSize = [81 18] CurrentFigure = [1] Diary = off DiaryFile = diary Echo = off FixedWidthFontName = Courier Format = short FormatSpacing = compact Language = russian MonitorPositions = [0 0 1024 768] More = off PointerLocation = [376 361] PointerWindow = [0] RecursionLimit = [500] ScreenDepth = [32] ScreenPixelsPerlnch = [116] ScreenSize = [1 1 1024 768] ShowHiddenHandles = off Units = pixels BeingDeleted = off ButtonDownFcn = Children = [] Clipping = on CreateFen = DeleteFcn = BusyAction = queue HandleVisibility = on HitTest = on Interruptible = on Parent = [] Selected = off SelectionHighlight = on Tag = Type = root UIContextMenu = [] UserData = [] Visible = on Познакомимся более подробно с каждым из свойств объекта Root, тем более, что многие из них будут повторяться и в других объектах.
262 Глава 7 Термин Callback довольно часто встречается в документации в сочетании СО словами Object (объект) И Function (функция, сокращенно— Fen). Он немного непривычен для программистов, работавших в визуальных средах, но достаточно понятен по смыслу. Речь идет об объекте, который в данный момент явился инициатором некоторого события (caiibackobject), и функции-обработчике данного события (calibackFunction). Префикс callback, символизирующий "потусторонний вызов", просто означает, что действия, связанные с возникшим событием и его обработкой, инициируются не выполняющейся программой, а поведением пользователя и средой, управляющей прохождением задач. Значением свойства Caiibackobject является указатель на активизированный таким образом объект, если тот в данный момент существует. Свойство commandwindowSize определяет текущие размеры (ширину и высоту) командного окна в текущих единицах измерения длин (см. значение свойства units). Свойство CurrentFigure задает номер текущего графического окна (i в приведенном выше примере). В качестве такового может выступать только что созданное графическое окно либо активизированное пользователем или программой в результате выполнения одной из команд: D figure (п) % — окно с указателем h выдвинуто на передний план; □ set (0, 'CurrentFigure' ,h) % — активизировано окно с указателем h. Два следующих свойства — Diary и DiaryFile — связаны с ведением протокольного файла, в который могут быть записаны все шаги, фиксирующие ваши операции во время сеанса, т. е. то, что дублируется в окне History Command (История команд). Запись Diary=off означает, что запись в протокольный файл отключена. Свойство Echo, принимающее значение on (включено) или off (выключено), связано с возможностью повторения текста выполняемых команд m-файла в командном окне. Во время отладки программы включение такого эха может оказаться полезным. Свойство FixedwidthFontName определяет имя моноширинного (ширина всех символов одинакова) шрифта, который используется в командном окне. В противоположность этому, Windows располагает большим количеством пропорциональных шрифтов, в которых существуют узкие (например — 1, i) и широкие символы (например — w, щ). Их применение привело бы к плавающей ширине колонок в выводимых таблицах. Свойства Format и Formatspacing задают формат вывода числовых данных, наличие или отсутствие дополнительных пустых строк. Выбор их значений подробно обсуждался в гл. 2.
Иерархия графических объектов и их свойства 263 Свойство Language отражает текущий язык, установленный в операционной системе. Свойство MonitorPositions определяет координаты левого верхнего угла монитора (0, 0) и разрешение в пикселах, установленное в данный момент (1024x768). При выводе данных, объем которых превышает размеры экрана, полезно установить режим постраничного вывода (моге=оп), который приостанавливает работу программы после заполнения области вывода. Для продолжения работы достаточно нажать любую клавишу. Такая возможность была предусмотрена еще в операционной системе MS-DOS. Свойство Pointer-Location фиксирует текущие координаты (х, у) курсора мыши в графическом окне, указатель которого хранится в свойстве pointerwindow. В нашем примере этот указатель равен 0 (указатель на объект Root), т. к. ни одного графического окна еще не было создано. В свойстве RecursionLimit задается глубина рекурсии, т. е. максимальное количество вложенных обращений к m-функциям. По достижению указанного лимита выполнение программы будет прервано. В свойстве ScreenDepth хранится количество битов, отводимых для хранения компонентов цвета одного пиксела. Свойство screenPixeisPerinch определяет количество пикселов, приходящихся на 1 дюйм. Им можно воспользоваться при масштабировании изображения на экране с другим разрешением. Текущие координаты левого верхнего и правого нижнего углов объекта Root в пикселах фиксируются в векторе screensize (в нашем примере установлено разрешение 1024x768, и объект занимает весь экран). При измерении длин в пикселах левый верхний угол имеет координаты (1, 1), во всех остальных единицах измерения ему соответствует точка с нулевыми координатами. Обратите внимание на положение начала координат в нижнем левом углу, что характерно для всех математических учебников в отличие от экранной системы координат, к которой привыкли программисты. Свойство showHiddenHandies определяет, надо ли показывать объекты, чьи указатели помечены как скрытые. Это напоминает возможности таких оболочек, как Norton Commander или ДИСКо Командир по отображению имен файлов с атрибутом hidden (скрытый). В свойстве units хранится установленная система измерения длин. Допустимый набор значений представляют следующие константы: П normalized — при этом левым нижним углом поля вывода считается точка с координатами (0, 0), правым верхним — точка с координатами (1.0, 1.0). Приведением программных значений координат к фактическому размеру окна занимается система. Это позволяет менять размеры графического окна с одновременной адаптацией поля графика;
264 Глава 7 D pixels — все размеры задаются в пикселах, и пересчет программных координат в пикселы выполняется программой пользователя; □ inches — все размеры задаются в дюймах (1 дюйм = 2,54 см) и не меняются при изменении габаритов графического окна; □ centimeters — все размеры задаются в сантиметрах и не меняются при изменении габаритов графического окна; D points — все размеры задаются в пунктах (1 пункт = 1/72 дюйма = = 0,3528 мм) и не меняются при изменении габаритов графического окна; D characters — размеры измеряются в "буквах". За ширину "буквы" принимается ширина буквы "х" шрифта, установленного в операционной системе по умолчанию, а за высоту— расстояние между базовыми линиями двух смежных строк текста. Выбор такой единицы измерения длины позволяет создавать приложения, имеющие одинаковый внешний вид на компьютерах, управляемых различными операционными системами. По умолчанию для объекта Root измерения производятся в пикселах. Однако при построении графиков функций наиболее удобным является режим normalized, который и установлен для объектов типа Figure по умолчанию. Задание координат в единицах типа "сантиметры", "дюймы" или "пункты" полезно при выводе на принтер документов, где должны быть соблюдены абсолютные размеры. Довольно многие свойства "описаны в классе Root только для того, чтобы быть переданными по наследству порожденным классам. Очень немногие из них имеют смысл для самого объекта Root. Однако мы объясняем их назначение с единственной целью — не повторять соответствующий материал в последующих разделах. Свойства BusyAction (действие в случае занятости) и interruptibie (возможность прерывания) определяют режим обработки текущего события в момент возникновения нового события. Для объекта, вызвавшего текущее событие, СВОЙСТВО Interruptibie Может быть разрешено (lnterruptible=on, по умолчанию) или запрещено (interruptibie=off). В первом случае обработка текущего события прерывается, обрабатывается вновь поступившее событие, а затем продолжается обработка прерванного события. Во втором случае существуют две возможности: D обработка текущего события прекращается (если BusyAction=cancel) и начинается обработка вновь поступившего события; D вновь поступившее событие устанавливается в очередь и ждет завершения обработки текущего события (если BusyAction=queue).
Иерархия графических объектов и их свойства 265 Свойства ButtonDownFcn, CreateFcn И DeleteFcn хранят указатели на функции, соответственно обрабатывающие события "Щелчок мышью на объекте", "Создание объекта1' и "Удаление объекта". Местоположение объекта в иерархии существующих объектов определяется свойствами Parent (родитель) и children (потомки). Первое из них представлено указателем на породивший объект, чьи данные и методы наследует текущий объект. В качестве значения второго свойства выступает вектор указателей на объекты, порожденные данным и не помеченные как невидимые. Естественно, что у объекта Root родитель отсутствует, а его дочерними объектами являются все видимые графические окна, созданные к настоящему моменту. Свойства Selected и SelectionHighiight принимают значения on ИЛИ off в зависимости от того, выделен ли данный объект и отмечен ли он повышенной яркостью. Для разных объектов такое выделение может быть представлено разными способами. Например, выделенный график функции помечается черными маркерами вдоль кривой, .выделение строки списка достигается путем инвертирования цвета, у выделенного окна изменяется цвет заголовка и т. п. Если графические построения выходят за пределы отведенной области, то они, как правило, отсекаются (ciipping=on). Но в некоторых ситуациях бывает полезно увидеть отсекаемую часть изображения, и тогда режим отсечения можно запретить (clipping-of f). Свойство Туре (тип) определяет принадлежность объекта тому или иному классу. Если класс Root представлен единственным объектом с типом Type=root, то другие классы могут быть представлены разными объектами с общим типом. Например, все графические окна имеют тип figure. Обратите внимание на свойство Tag (дословно — ярлык, этикетка, бирка), значением которого может быть любая строка, присваиваемая пользователем. Для того чтобы различать между собой объекты одного класса, их свойствам Tag можно присвоить разные ярлыки. Конечно, это далеко не единственный способ идентификации объектов, в частности, каждый объект имеет уникальный указатель. При создании графических объектов в среде GUIDE (Graphical User Interface Development Environment) свойству Tag значения присваиваются автоматически, например — editl, edit2 и т. д. Началом такого имени служит тип объекта, а дописываемый числовой индикатор определяет порядковый номер объекта данного типа. Свойство visible, которое может принимать одно из двух значений: on или off, определяет видимость объекта на экране. Если какой-то объект объявлен невидимым, то его указатель может попасть в список указателей свойства childern, если родительское свойство showHiddenHandies разрешает это сделать.
266 Глава 7 Свойство HitTest управляет режимом выбора текущего объекта по щелчку мыши. Если его значение отключено (HitTest=off), то щелчок мыши при- , ВОДИТ К Сбросу Значения свойства CurrentObject (CurrentObject=[]). Почти к любому графическому объекту может быть добавлено контекстное меню, появляющееся при нажатии правой кнопки мыши в тот момент, когда курсор находится над данным объектом. Указатель на такое меню хранится В свойстве UIContextMenu. Значением свойства userData может быть любая матрица с данными, которая ассоциирована с объектом. Для корневого объекта такие данные великого смысла не имеют. Однако пользователю предоставляется возможность установить какие-то значения этого свойства с помощью функции set, изменить их в процессе выполнения программы и опросить текущие значения с помощью функции get. 7.2. Объект Figure Графические окна являются объектами, порождаемыми по шаблону класса Figure. Об этом свидетельствует свойство Туре, которое для любого графического окна принимает значение figure. Существует несколько способов создания графических окон. Во-первых, можно прибегнуть к услугам функции figure: » h_Fig = figure; » h_Fig = figure ('Свойство_1',Значение_1,... *Свойство_2',Значение_2,...); В первом случае создается новое графическое окно, которому система присваивает значения свойств по умолчанию. Во втором случае вновь создаваемому объекту присваиваются значения указанных свойств, а неупомянутые свойства устанавливаются системой по умолчанию. В обоих случаях функция figure возвращает указатель на созданный объект, который становится текущим, заслоняя собой остальные окна, находящиеся на экране. Однако мы воспользуемся другим способом — построим график синусоиды и отобразим все свойства текущего окна (пример 7.2). кл.Г..,.......".-; йв,,.й ,..;i..&s^:i«(«&ftSiiWffi, *nrf«» ^s^^s^MSSi^^ig^^i^si&.4mmimss^ » х=6:0.2:6.28; » y=sin(x); » plot (х, у) » h_Fig=g.cf ; » getfh Fig) % Отображение всех свойств текущего окна
Иерархия графических объектов и их свойства 267 Alphamap =1 [1 by 64) double array] BackingStore = on CloseRequestFcn = closereq Color = [0.8 0.8 0.8] Colormap = [ (64 by 3) double array] CurrentAxes = [101.001] CurrentCharacter = CurrentObject = [] CurrentPoint = [0 0] DockControls = on DoubleBuffer = on FileName = FixedColors = [ (10 by 3) double array] IntegerHandle — on InvertHardcopy = on KeyPressFcn = MenuBar = figure MinColormap = [64] Name = NextPlot = add NumberTitle = on PaperUnits = centimeters PaperOrientation = portrait PaperPosition = [0.634517 6.34517 20.3046 15.2284] PaperPositionMode = manual PaperSize = [20.984 29.6774] PaperType = A4 Pointer = arrow PoihterShapeCData = [ (16 by 16) double array] PointerShapeHotSpot = [1 1] Position = [120 90 560 420] Renderer = painters RendererMode = auto Resize = on ResizeFcn = SelectionType = normal ShareColors = on 'ToolBar = auto Units = pixels
268 Глава 7 WindowButtonDownFcn = WindowButtonMotionFcn = WindowButtonUpFcn = WindowStyle = normal WVisual = [ (1 by 77) char array] WVisualMode = auto BeingDeleted = off ButtonDownFcn = Children = [101.001] Clipping = on CreateFcn = DeleteFcn = BusyA'ction = queue HandJeVisibility = on HitTest = on Interruptible = on Parent = [6] Selected = off SelectionHighlight = on Tag = Type = figure UICbntextMenu = [] UserData = [] Visible = on Специфика графического окна, характеризующаяся наличием главного меню и области, в которой могут быть расположены различные графические объекты нижних уровней (оси, компоненты для организации интерфейса с пользователем и др.), привела к появлению довольно большого числа новых свойств, которых не было у родителя — объекта Root. Тем не менее порядка 20 свойств, содержащихся в предыдущем разделе, унаследовано графическим окном, и к повторному их описанию мы возвращаться не будем. Положение вновь создаваемого графического окна на экране определяется его свойством Position, в качестве значений которого выступает четырех- элементный вектор [left bottom width height]. Смещения left и bottom задают положение нижнего левого угла, а два следующих компонента — ширину и высоту окна в пикселах. Графическое окно может быть обычным (windowstyie=normai) или модальным (windowStyie=modai). В первом случае его можно переместить, изменить размеры или закрыть. Во втором случае окно ждет только определенного события со стороны пользователя (ввода данных, нажатия кнопки
Иерархия графических объектов и их свойства 269 и т. п.). Без этого события окно не может быть уничтожено, и работа программы, соответственно, не может быть продолжена. Окну присвоен стандартный заголовок Figure 1. Дополнительный заголовок графического окна в виде строки хранится в свойстве Name. По умолчанию это свойство представлено пустой строкой, и в заголовках окон мы видим надписи типа Figure 1, Figure 2, и т. д. Если свойству Name присвоить какое- либо значение, например, h_Fig.Name = 'Оптимизация f(x)' то заголовком окна будет строка вида: Figure 1 : Оптимизация f (х) Можно отказаться от стандартной нумерации окон (Figure 1, Figure 2 и т. д.), если присвоить свойству NumberTitie значение off. Свойство Мептдваг управляет отображением стандартного главного меню графического окна. В режиме MenuBar=figure это меню создается и отображается, в режиме мегшваг=гюпе — не создается и не отображается. Независимо от значения этого свойства мы можем выполнить команду uimenu, чтобы создать нестандартное меню графического окна. Свойство Backingstore, принимающее значение on или off, управляет "использованием специального буфера, расположенного1 в оперативной памяти и применяемого для запоминания копии окна во время работы программы. Если часть окна перекрывается на экране, то его содержимое может быть быстро восстановлено путем копирования буфера в видеопамять. Когда пользователь пытается закрыть графическое окно (это можно сделать разными способами — нажать кнопку с крестиком в заголовке окна, выбрать в меню команду Close (Закрыть) или выйти из системы MATLAB), возникает событие "Запрос на закрытие". На это событие может отреагировать специальный обработчик, предусмотренный программистом, или системная программа, если пользователя усфаивают действия системы по умолчанию. А сводятся системные действия к тому, что все скрытые указатели из режима off переводятся в режим on, и все созданные объекты удаляются. Соответствующая системная функция имеет имя closereq, которое ПО умолчанию присвоено СВОЙСТВУ CloseRequestFcn. Один из вариантов пользовательского обработчика указанного события приведен в документации и его слегка переработанный текст представлен в примере 7.3. % my_closereq selection = questdlg('Закрыть указанное окно?',... 'Close Request Function','Yes',?№>','Yes'); ч
270 Глава 7 switch selection, case 'Yes' delete(gcf) case 'No' return end Теперь остается заменить системный обработчик для окна с указателем h_Fig на наш: set(h_Fig,'CloseRequestFcn','my_closereq') Значение свойства color определяет цвет фона в графическом окне с помощью вектора из трех чисел, задающих интенсивность каждой из трех RGB-составляющих. По умолчанию у всех окон цвет фона серый, и ему соответствует комбинация [0.8 0.8 0.8]. Свойство coiormap представлено матрицей из m строк (по умолчанию m=64, максимальное значение для Windows — 256). В каждой строке этой матрицы задано 3 вещественных числа, соответствующих интенсивности RGB-coc- тавлющих. Таким образом, матрица задает набор допустимых цветовых оттенков (coiormap — дословно, карта цветов), в которые могут быть окрашены различные объекты в окне. Использовать однобайтовый индекс строки гораздо экономичнее, чем указывать три соответствующих вещественных числа. Минимальное количество строк в массиве Coiormap определяется значением свойства MinCoiormap. Матрица фиксированных цветов FixedCoiors, также представленная матрицей размерности /ихЗ, предназначена для запоминания нестандартных цветов, не попавших в свойство Coiormap. В этой дополнительной матрице могут храниться нестандартные цвета меток, линий, текстов и визуальных компонентов. В графическом окне функция plot автоматически создала объект типа Axes, присвоив ему указатель — вещественное число ю.1.001 (см. значение свойства CurrentAxes). Поэтому у фигуры появился первый потомок (chiidren=[ioi.OOi]). В свою очередь, родителем фигуры является объект Root (parent=[0]). Так как мы еще не сохраняли текущее графическое окно в файле с расширением fig, то значение свойства FileName пока не определено. Одним из важнейших свойств любой графической системы является текущая точка, координаты которой [х,у] хранятся в векторе CurrentPoint. В момент создания графического окна эта точка устанавливается в начало координат, расположенное в левом нижнем углу фигуры. Затем система отслеживает перемещения курсора мыши по графическому окну и изменяет координаты текущей точки перед тем, как обратиться к одной из функций обработки следующих событий: "Нажатие кнопки мыши", "Отпускание кнопки мыши" и "Перемещение мыши". В каждом из обработчиков указанных событий мы можем обратиться к свойству CurrentPoint, чтобы опреде-
Иерархия графических объектов и их свойства 271 лить текущее положение курсора мыши. Если ни один из перечисленных обработчиков события не предусмотрен, изменение координат текущей точки происходит в момент щелчка кнопкой мыши на территории графического окна. Свойство NextPiot управляет способом отображения нового графика в уже существующем окне. По умолчанию NextPiot=add, что сохраняет ранее установленные значения всех свойств. Если установить свойство NextPiot= =repiace, то у окна восстанавливаются значения всех свойств по умолчанию, кроме свойства Position, и удаляются все порожденные объекты (children). Третья возможность (№xtPiot=repiacechiidren) сохраняет все свойства текущего окна, но удаляет порожденные объекты. Довольно широкие возможности по конфигурации указателя мыши в зависимости от выполняемой операции предоставляют свойства Pointer и PointerShapeCData. Первое из них может принимать одно из 17 стандартных значений: crosshair, arrow, watch, topi, topr, botl, botr, circle, cross, fleur, left, right, top, bottom, fullcrosshair, ibeam, custom. Полужирным шрифтом выделено значение по умолчанию, которому соответствует стандартная стрелка. Последнее значение (custom — по выбору) разрешает пользователю сформировать шаблон своего курсора в виде массива размером 16x16, представляющего значение свойства PointershapeCData. Значениями элементов такого массива могут быть: 1 — для обозначения черных точек, 2 — для обозначения белых точек, Ыак — для обозначения прозрачных точек. В примере 7.4 приведен фрагмент создания образа курсора в виде квадрата с прозрачной серединой, заимствованный из книги [3J и слегка подправленный. г^'^г"^'"1^'"'"....rr~;^"™T""~:w"-s*»v, , "?% v^K"""7""'^x £""у"—----,^ » MP = ones (16,16') ; % матрица 16x16 из единиц » MP(2:15,2:15)=NaN; % заполнение прозрачных "точек" » set(gcf,'Pointer','custom') » set(gcf,'PointerShapeCData',MP) » set(gcf,'PointerShapeHotSpot',[1 1]) Для нестандартного пользовательского курсора бывает полезно определить характерную точку в шаблоне, которая соответствует указываемой позиции на экране. По умолчанию таковой считается левый верхний угол шаблона, который в локальной системе координат курсора имеет координаты (1, 1). Эта система координат не совпадает с обычными координатами MATLAB, она ближе к экранной системе координат. Целеуказывающая точка нестан-
272 Глава 7 дартного шаблона задается в виде двухэлементного вектора [ i j ], присваиваемого СВОЙСТВУ PointerShapeHotSpot. Возможность изменять размеры графического окна с помощью мыши зависит от значения свойства Resize, по умолчанию равного on, что позволяет деформировать или перемешать окно. При Resize=off такие манипуляции запрещены. Изменение размеров окна или его перемещение вызывают автоматическую перестройку графика с возможным изменением маркировки координатных осей. Однако в поле графического окна могут находиться и другие компоненты — кнопки, списки, окна ввода и др. Для их перерисовки может понадобиться специальный обработчик события Resize — функция, указатель на которую помещен в свойство ResizeFcn. Обработчики подобного рода будут рассмотрены в гл. 9. Несколько свойств графического окна связано с получением твердой копии. При выводе на принтер или плоттер фоновый цвет может оказаться неприемлемым, т. к. созданный график лучше бы смотрелся на белом фоне (при этом можно было бы сэкономить и на расходе тонера). Если свойству invertHardcopy присвоено значение on, то MATLAB на время печати выполнит такую замену. В случае invertKardcopy=off принтер постарается тем или иным способом соблюсти цветовую гамму графического окна (цветной — цветом, черно-белый — полутонами). Свойства, начинающиеся со слова Paper, управляют параметрами страницы, на которой воспроизводится копия графического окна (табл. 7.2). Таблица 7.2 Имя свойства Назначение PaperUnits Установка единиц измерения (по умолчанию — centimeters) PaperOrientation Ориентация листа бумаги, по умолчанию — портретная (portrait). Альтернативное расположение — альбомная (landscape) РарегТуре Формат листа бумаги (по умолчанию — А4) Paper size Размер листа бумаги [width height] (по умолчанию — [210 297]) PaperPosition Четырехкомпонентный вектор [xl yl х2 у2], задающий положение прямоугольной области на листе, в которой должно быть воспроизведено графическое окно. Началом координат считается левый нижний угол листа. Точка (xl, yl) определяет положение левого нижнего угла прямоугольника, точка (х2, у2) — правого верхнего
Иерархия графических объектов и их свойства 273 Таблица 7.2 (окончание) Имя свойства Назначение PaperPositionMode Способ размещения графического окна на листе. При PaperPositionMode=iranual положение рисунка задается вектором PaperPosition. При PaperPositionMode=auto система пытается отобразить окно в такой позиции, в какой оно находится на экране (WYSIWYG — то, что вы видите, то и получится) При различных перемещениях отображаемых объектов по экрану приходится каждый раз выполнять довольно большой объем вычислительной работы — пересчитывать координаты характерных точек графического объекта, освещенность и отражательную способность его граней и т. п. Этот процесс называют визуализацией векторного изображения или рендерингом. Чем эффективнее алгоритм решения такой задачи, тем более реалистично выглядит отображаемый объект и тем быстрее перемещается по экрану. MATLAB предлагает пользователю три варианта для выбора алгоритма рендеринга. Значение Renderer=painters соответствует оригинальному алгоритму разработчиков пакета, и он достаточно эффективно обрабатывает простые или небольшие графические объекты. Значение Renderer=zbuffer позволяет подключить известный алгоритм Z-буфера, в котором удаление невидимых деталей осуществляется за счет анализа расстояний отображаемых точек до поверхности экрана. Наиболее мощный и самый эффективный набор алгоритмов отображения предлагает библиотека методов OpenGL, которая на большинстве современных компьютеров поддерживается и аппаратными средствами. Если вы с помощью команды opengl info убедитесь в такой поддержке на своем компьютере, то самый лучший результат будет получен при Renderer=OpenGL. Выбор метода рендеринга в зависимости от сложности отображаемого объекта по умолчанию выполняет система, т. к. свойству RendererMode присвоено значение auto. Использование мыши для выделения какого-либо интерфейсного элемента допускает различные действия со стороны пользователя — щелчки (обычно левой кнопкой мыши), двойные щелчки (время между двумя последовательными щелчками не превышает некоторого лимита времени, установленного в системе), щелчки в сочетании с нажатой клавишей <Shift>, <Alt> или <Ctrl>. Каждое из таких событий может быть ассоциировано с разными программными откликами, например, двойной щелчок по имени файла должен привести к его открыванию, щелчок по графическому объекту может перевести его в режим перемещения или изменения размера и т. п. Свойство seiectionType хранит информацию о способе, который был из-
274 Глава 7 бран пользователем при последней операции с мышью. Его значениями могут быть следующие величины: D normal, что соответствует обычному щелчку левой кнопкой; □ extend, что соответствует щелчку левой кнопкой с одновременно нажатой клавишей <Shift> или одновременному щелчку обеими кнопками; □ ait, что соответствует щелчку правой кнопкой или сочетанию клавиши <CtrI> с щелчком левой Кнопкой; □ open, что соответствует двойному щелчку любой кнопкой мыши. В момент, когда указатель мыши находится в области графического окна, пользователь может быть инициатором следующих событий: □ "Нажатие кнопки мыши" — обработчик этого события определяется строкой, заданной в качестве значения свойства windowButtonDownFcn; □ "Отпускание кнопки мыши" — обработчик этого события определяется строкой, заданной в качестве значения свойства windowButtonUpFcn; П "Перемещение мыши" — обработчик этого события определяется строкой, заданной в качестве значения свойства windowButtonMotionFcn; □ "Нажатие клавиши на клавиатуре" — обработчик этого события определяется строкой, заданной в качестве значения свойства KeyPressDown. Строки, представляющие значения этих свойств, задают имена обработчиков соответствующих событий. В роли таких обработчиков могут выступать либо заранее подготовленные m-файлы, либо строки, содержащие выражения, которые MATLAB может исполнить. Если обработчику KeyPressFcn передается управление, то символ, соответствующий нажатой клавише, можно извлечь из свойства currentcharacter-. Программа обработки этого события может также обратиться к свойству pointerwindow объекта Root, чтобы узнать, в каком графическом окне в этот момент находился курсор мыши. Вектор-строка Aiphamap имеет отношение к отображению трехмерных объектов в графическом окне. Он содержит набор числовых значений в диапазоне [0, 1], которые могут быть приписаны к RGB-компонентам каждого пиксела для определения степени его прозрачности. Палитра RGBA позволяет отображать объекты, сквозь которые просвечивают другие объекты заднего плана. 7.3. Объект Axes Объект axes, представляющий график функции в графическом окне, является наиболее сложным, ибо содержит довольно много составляющих — собствен-
Иерархий графических объектов и их свойства 275 но оси с их подписями и разметкой, линии графиков с их маркировкой и соответствующими подписями, легенды, возможность увидеть объект из разных позиций наблюдателя и многое другое. В примере 7.5 приведен список всех свойств текущих осей, на которых был построен график синусоиды. » get(gca) ActivePositionProperty = outerposition ALim = [0 1] ALimMode = auto AmbientLightColor = [1 1 1] Box = on CameraPosition = [3.5 0 17.3205] CameraPositionMode = auto CameraTarget = [3-.5 0 0] CameraTargetMode = auto CameraUpVector = [0 1 0] CameraUpVectorMode = auto CameraViewAngle = [6.60661] CameraViewAngleMode = auto CLim = [0 1] CLimMode = auto Color = [1 1 1] CurrentPoint = I (2 by 3) double array] ColorOrder = [ (7 by 3) double array] DataAspectRatio = [3.5 1 1] DataAspectRatioMode = auto DrawMode = normal FontAngle = normal FontName = Helvetica FontSize = [10] FontUnits = points FontWeight = normal GridLineStyle = : Layer = bottom LineStyleOrder = - LineWidth = [0.5]
276 Глава 7 MinorGridLineStyle = : NextPlot = replace OuterPosition = [0 0 1 1] PlotBoxAspeetRatio = [1 1 1] PlotBoxAspectRatioMode = auto Projection = orthographic Position = [0.13 0.13 0.775 0.815] TickLength = [0.01 0.025] TickDir = in TickDirMode =■ auto Tightlnset = [0.047619 0.0396825 0.00892857 0.0176571] Title = [102.001] Units = normalised View = [0 90] XColor = [0 0 0] XDir = normal XGrid = off XLabel = [103] XAxisLocacion = bottom XLim = [0 7] XLimMode = auto XMinorGrid = off XMinorTick = off XScale = linear XTick = [ (1 by 8) double array] XTickLabel = 0 1 2 3 4 5 6 7 XTickLabelMode = auto XTickMode = auto YColor = [0 0 0] YDir = normal
Иерархия графических объектов и их свойства 277 YGrid. = off YLabel = [104] YAxisLocation = left YLim = [-1 1] YLimMode = auto YMinorGrid = off YMinorTick = off YScale = linear YTick = [ (1 by 11) double array] YTickLabel = [ (11 by 4) char array] YTickLabelMode = auto YTickMode = auto ZColor = [0 0 0] ZDir = normal ZGrid = off ZLabel = [105] ZLim = [-11] ZLimMode = auto ZMinorGrid = off ZMinorTick = off ZScale = linear ZTick = [-10 1] ZTickLabel = ZTickLabelMode = auto ZTickMode = auto BeingDeleted = off ButxonDownFcn = Children = [3.00098] Clipping = on CreateFcn = DeleteFcn = BusyAction = queue HandleVisibility = on HitTest = on Interruptible = on Parent = [1] Selected = off SelectionHighlight = on
278 Глава 7 Tag = Type = axes UICoiitextMenu = [] UserData = [] Visible = on Свойство осей position позволяет нам определить положение осей в графическом окне. Например, оператор h_Ax ^ axes{'Position",[х у w h]}; создает объект типа Axes с указанной позицией и возвращает указатель на созданный объект. Координаты (х, у) задают позицию левого нижнего угла прямоугольного поля графика. Ширина w и высота h определяют размеры прямоугольника. Эти величины задаются в единицах, соответствующих значению свойства Units. По умолчанию для осей MATLAB использует Units=normaiized, когда точка (о, о) соответствует левому нижнему углу, а точка (1.0,1.0)— верхнему правому углу графического окна. В пределах одного графического окна могут быть объявлены несколько осей (пример 7.6). : .--.--; ■■■■■:■ ..г..ТГг- v-.^^^.^.y.y........... ..,.v.,..,v.^..^-..t....,....,...,...,.,„.. .,.,„..,..,..,.....,.......„„ ; I Пример 7.6. Неркрль«о;.оре|^й;Од||ом р^б.^^^^^^^у- -:, .,.-, _,.. ■> "- - ■ » axes ('position',[.1 .1 .8 .6]) » mesh(peaks(40) ) ; » axes('position',[.1 .8 .8 .1]) » pcolorl [1:10,-1:10]) ; Результат построения этих двух совершенно разнородных графиков приведен на рис. 7.2. Стиль линий, которыми рисуются оси графика, и их толщины регулируются свойствами Linestyieorder и Linewldth. Возможные значения этих свойств подробно обсуждались в гл. 2. Пример графика с утолщенными осями (Linewidth=4) приведен на рис. 7.3. Около 40 свойств управляют параметрами координатных осей. Комментарии к этим свойствам, повторяющимся по каждой из трех осей, приведены в табл. 7.3.
Иерархия графических объектов и их свойства 279 Рис. 7.2. Совмещение двух объектов типа Axes в одном окне 1 D.5 0 -DJ5 [ У / ' / / 1 f 1 1 ] 1 ~\ \ 2 3 \ -4 / / / 5 6 •? ?:'*■ ■ U ! .Г - >3 ■;i Рис. 7.3. График с утолщенными осями Таблица 7.3 Свойство XColor XDir XGrid XLabel Значение [rx gx bx] normal 1 reverse on | off [px] Пояснение RGB-компоненты цвета оси x Направление оси х Наличие или отсутствие сетки, перпендикулярной к оси X Указатель на подпись под осью х ЮЗак 899.
280 Глава 7 Таблица 7.3 (окончание) Свойство Значение Пояснение XAxisLocation XLim XLimMode XMinorGrid XMinorTick XScale XTick XTickLabel bottom I top [xmin xmax] auto I manual on | off on I off linear | log Массив чисел ixnx Массив строк nxxl XTickLabelMode auto | manual XTickMode auto I manual Положение оси x Пределы изменения по оси х Режим выбора пределов изменения Наличие или отсутствие мелкой сетки, перпендикулярной к оси х Наличие или отсутствие мелких штрихов по оси х Масштаб по оси х Координаты меток по оси х Значения меток по оси х Режим формирования меток Режим нанесения меток Еще несколько свойств принимают участие в оформлении поля графика: □ Title — заголовок графика; О Projection — задание проекции (orthographic ИЛИ perspective); П GridLineStyle — стиль построения крупной координатной сетки; О MinorGridLinestyle — стиль построения мелкой координатной сетки; D TickLength — двухкомпонентныи вектор, задающий длины штрихов для 2D- и ЗО-графиков; П TickDir — направление штрихов на осях (in — внутрь, out — наружу); П TickDirMode — реЖИМ НЭНесеНИЯ ШТРИХОВ (auto ИЛИ manual). В поле графика находится довольно много текстовых характеристик — маркировка осей и штрихов, подпись графика. Поэтому объект Axes обладает рядом свойств, управляющих параметрами используемого шрифта: П FontName — имя шрифта; □ Fontunits — единицы измерения высоты символов; О Fontsize — высота символов; D FontWeight — ПрИЗНЭК уТОЛЩеНИЯ КОНТура (light — ТОНКИЙ, normal — нормальный, demi — полужирный, bold — жирный); О FoncAngle — наклон шрифта (normal — Прямой, italic — Курсив, oblique — НЭКЛОННЫЙ).
Иерархия графических объектов и их свойства 281 Свойства, названия которых включают сочетание AspectRatio, позволяют отказаться от автоматического масштабирования и переключиться в ручной режим управления шагами вдоль каждой из координатных осей. Для этих целей гораздо удобнее воспользоваться функцией axis: axis normal; axis square; axis equal; Результаты такого управления приведены на рис. 7.4—7.6. Группа свойств, названия которых начинаются со слова Camera, управляет параметрами точки зрения. В точке с координатами CameraPosition находится камера, наблюдающая за графическими объектами, размещенными на поле Axes. Оптическая ось камеры нацелена на точку с координатами CameraTarget. Угол обзора объектива камеры определяется значением параметра CameraViewAngle. Наконец, компоненты вектора CameraUpVector определяют поворот камеры вокруг оптической оси. Сцена, которую мы наблюдаем на экране, представляет собой изображение, запечатленное камерой. Каждый из перечисленных выше параметров либо выбирается системой автоматически, либо назначается пользователем. Варианты выбора определяются значениями СВОЙСТВ CameraPositionMode, CameraTargetMode, CameraViewAngleMode И CameraUpVectorMode. -> Figure 1 File- Ecjlt View Insert Tools Desktop Window, He(p. dc*e-@if¥l^■«о®|'«;i Dm\«3 D " ,. .0.5' f'''p-Ж. Q ■ -0.5 1.Л- . ■V: ' " ' '''" ' -:"' / \ / \ \ \ \ \ У ......1-'.-.; ■ .2',..;- -3- „.' 4 V~ / / . 1 . J- ^-*• ».f - *- ' / - 6 Y V ■: НПИ '" /"■ * .-7-,^--.- - - ■ r,% , ■%■"! Рис. 7.4. Автоматический выбор шагов по обеим осям
282 Глава 7 »> Figure 1 File Edit View InserM[ools Desktop Window Help ЯПП \ , / * Рис. 7.5. График в квадратной области -> Figure 1 File Edit View- insert Tools Desktop Window Help _ ..: НПО I-:-... d.b* q в IfFJ.ei ^ ■*■> ® i«! D В1 в о i;.5 .! s* 1 1 \ 0.5 :0 " ^5. "-1 -1.5 ( ^- У N \ \ ) 1.2 3 4 - / У ' 5 6 1 Л J i :4=4) L ." Рис. 7.6. График с равными шагами по обеим осям
Иерархия графических объектов и их свойства 283 7.4. Объект Line Объекты типа Line создаются почти всеми функциями построения плоских И пространственных кривых (plot, semilogx, semilogy, loglog, plotyy, plots), которые возвращают указатель на появляющуюся кривую. Еще один способ создания таких объектов предлагает функция line, допускающая несколько вариантов обращения: h_Lin = line(X,Y); % построение плоской кривой h__Lin = line(X,Y,Z); % построение пространственной кривой h_Lin = line(X,Y,Z,'свойство!',значение!,... 'свойство2',значение2,...); h_Liri = line ('свойство1', значение1, .. . 'свойство2',значение2,...); Для плоских кривых вектор х представляет собой набор значений независимой переменной, а вектор у — набор соответствующих значений функции >■(*). Таким образом, каждая точка плоской кривой задается парой координат (Xj, yj). В случае пространственной кривой каждая ее точка представлена тройкой координат (х/, yh ц). Построение кривой происходит в области текущего объекта типа Axes, где каждая пара соседних точек соединяется отрезком прямой. Выведем список свойств линии после построения графика синусоиды (пример 7.7). ! Пример 7.7. Свойства объекта liine ""■ ';<0 Ш^Щ'^фШгШ0Ш0^Шй. "Ч^Ш » x=0:0.1:2*pi; >> y=sin(x); » h_lin=plot(x,y); >> get(h_lin) Color: [0 0 1] EraseMode: 'normal' LineStyle: '-' LineWidth: 0.5000 Marker: 'none' MarkerSize: 6 MarkerEdgeColor: 'auto' MarkerFaceColor: 'none' XData: [1x63 double] YData: [1x63 double] .ZData: [1x0 double]
284 Глава 7 BeingDeleted: ButtonDownFcn: Children: Clipping: CreateFcn: DeleteFcn: BusyAction: HaridleVisibility: HitTest: Interruptible: Selected: SelectionHighlight: Tag: Type: UIContextMenu: UserData: Visible: Parent: DisplayName: XDataMode: XDataSource: YDataSource: ZDataSource: 'off [] [Oxl double] ■on' [] [] 'queue' 'on' ■on' •on' •off 'on' T 1 •line' [] [] 'on' 151.0079 1 1 1 manual■ f i T 1 1 1 По сравнению с предыдущими графическими объектами линия обладает совсем незначительным количеством свойств. Большинство из них вполне подробно были описаны в гл. 2. Поэтому мы достаточно бегло будем останавливаться на уже знакомых свойствах. Синусоида построена синим цветом (color=[0 о 1]). Этот цвет был выбран из последовательности цветов, заложенных в свойстве coiororder объекта Axes. При построении следующего графика в поле тех же осей из списка Coiororder будет выбран следующий цвет, и так до тех пор. пока не окажется исчерпанным весь список. Потом цикл повторится с самого начала. Свойство EraseMode управляет режимом взаимодействия цвета пикселов создаваемой линии с цветом пикселов поля графика. Значение по умолчанию — normal — приводит к тому, что пикселы кривой вытесняют пикселы области рисования. Так строится нормальная кривая. Другими возможными значениями свойства EraseMode являются попе (кривая не рисуется, воспроизводятся только маркеры), background (кривая прорисовывается цветом фона) и хог (цвета новых и старых пикселов взаимодействуют по операции
Иерархия графических объектов и их свойства 285 "исключающее ИЛИ"). Повторное рисование кривой по себе же в режиме хог приводит к ее стиранию. При этом проявляется цвет пикселов области рисования, в который они были окрашены до предыдущего рисования. График синусоиды построен сплошной линией (Linestyle=-). Когда график строится с помощью функции iine(x,Y,z) без указания стиля линии, то он выбирается автоматически из списка стилей, указанных в свойстве LinestyieOrder текущего объекта Axes (-, —, :, .:, none). Каждая новая линия строится своим стилем — по очередному значению в списке LineStyleOrder. Толщиной линии управляет значение свойства Linewidth, которое задается в пунктах (1 пункт = 1/72 дюйма = 0,3528 мм). Свойство Marker включает (символы, определяющие вид маркера, приведены в табл. 2.8) или отключает (попе) режим маркировки кривой. Размером маркеров управляет значение свойства MarkerSize, задаваемое в пунктах. Контуры маркера и его внутренняя область могут быть закрашены в цвета, определяемые значениями СВОЙСТВ MarkerEdgeColor И MarkerFaceColor. Значениями свойств XData, YData и ZData являются координаты точек кривой. Перечень оставшихся свойств'1 уже обсуждался в предыдущих разделах. Вместо них мы прокомментируем пример построения линии с тенью. Идея примера заключается в построении двух слегка смещенных друг относительно друга графиков. Причем теневой график имеет несколько большую толщину линии. Приведенный в примере 7.8 фрагмент без изменений заимствован из файлов помощи. • Пример 7-8. Построение линиИ'С тенью ..¾ *%•№£*•?£:■,•. -.-' - %■*:&■ - ч г...илг.;..^!.л;к.лй..Л'...л.л. л'.л^17^.-..л:..Ъ:.3>л»^.я^.Х-,лл:.-. ;л.'.Л:....&..1/.л. л й. .7¾ .:-:. л. . -." .< «,.*.>£. .*-.-.« » t = 0:pi/20:2*pi; » h_Linl = plot(t,sin(t),'k'); » h_Lin2 = line(t+.06,sin(t),'LineWidth',4,'Color',[.8 .8 .8]); » set(gca,'Children',[h_Linl h_Lin2]) Первая команда формирует массив аргументов t, который используется во второй команде для построения обычной синусоиды черным цветом. Третья команда использует смещенный аргумент t+о.Об и строит в этих точках утолщенную синусоиду серого цвета. Затем построенная тень заслоняет большую часть первой синусоиды, и наблюдаемая картина производит грустное впечатление (рис. 7.7). Зато четвертая команда осуществляет перестройку дочерних линий, выводя на передний план основную синусоиду (рис. 7.8).
286 Глава 7 Немного подумав, мы достигли такого же результата, изменив порядок построения кривых и сэкономив на этом одну команду: » t = 0:pi/20:2*pi; » h_Lin2 = plot(t+.06,sin(t),'LineWidth',4,'Color',[.8 .8 .8]); » h Linl = line(t,sin(t),'Color',[0 0 0]); ■■ ^ '-: 1 0.8 0.6 0,4 ■i™ л.; 0 - -0.2 -0.4 -0.6 -0.S -'< Ir" " / / •/ - - - - ] 1 1 2 \ V \ V :o \ 3 , 4 ./ / / / / / 5 6 I - - - - - - 7 Рис. 7.7. Неудачное расположение основного графика и его тени Рис. 7.8. Результат перемещения основной синусоиды на передний план
Иерархия графических объектов и их свойства 287 7.5. Объект Rectangle Объект типа Rectangle используется для отображения прямоугольников, прямоугольников с закругленными краями и эллипсов. Создаются такие объекты на поверхности текущих осей с помощью функции rectangle, возвращающей указатель на построенный прямоугольник: h_Rect = rectangle; h_Rect = rectangle ('Position', [к,y,w,h]) h_Rect = rectangle ('Position',[x, y,w,h],'Curvature', [rx,ry]) h_Rect = rectangle ('Свойство_1',Значение_1,... 'Свойство_2',Значение_2,...); Вызов функции без параметров эквивалентен следующему обращению: h_Rect = rectangle('Position",[0,0,1,1],'Curvature', [0,0]); Свойство Position определяет координаты левого нижнего угла (х, у), ширину w и высоту h прямоугольника. Нулевые значения свойства Curvature (кривизна) соответствуют построению прямоугольника. Максимальные значения составляющих rx, гу равны 1, и при них прямоугольник превращается в эллипс. Построим пару прямоугольников, чтобы познакомиться с другими свойствами этих объектов (пример 7.9). ^Пример 7.9. Протроение'^рймругольнйиов- ^^-¾^^¾¾^¾¾¾^.^¾^^^¾ » h_Rectl=rectangle('Position', {50, 50,300, 230]) ; » rectangle('Position',[70,70,200,150]); » get(h_Rectl) Curvature - [0 0] EraseMode = normal FaceColor = none EdgeColor = [0 0 0] LineStyle = - LineWidth = [0.5] Position = [50 50 300 200] BeingDeleted = off ButtonDownFcn = Children = [] Clipping = on CreateFcn = DeleteFcn =
288 Глава 7 BusyAction = queue HandleVisibility = on HitTest = on Interruptible = on Parent = [102.006] Selected = off SelectionHighlight = oh Tag = Type = rectangle UIContextMenu = [] UserData = [] Visible = on Их внешний вид показан на рис. 7.9. Первый прямоугольник имеет большие размеры, и его контуры напоминают границы поля графика. ■■ 250 :- 2ро 150 100 ■% ,■.,- = 0 100 150 200 250 300 '., .. з< - "1 50 Рис. 7.9. Вложенные прямоугольники В примере 7.10 приведен фрагмент программы, которая воспроизводит 4 квадрата с разными параметрами кривизны (рис. 7.10). ™........,...,..r.,.,.t....„,...v.,™„„., ..^.^„,?„.^...ф.....„ ,„..„„„,.; Г: Пример Х1.0; ПбстрАещё.^ » xlim( [0, 0. 7]) % пределы изменения по оси х » ylim([0,0.7]) % пределы изменения по оси у
Иерархий графических объектов и их свойства 289 » daspect([1,1,1J) % одинаковые шаги по осям » rectangle С Position',[0.1,0.1,0.5,0.5],'Curvature',[0.1,0.1]) » rectangle('Position',[0.1,0.1,0.5,0.5],'Curvature',[0.5,0.5]) » rectangle('Position',[0.1,0.1,0.5,0.5],'Curvature',[0.75,0.75]) » rectangle('Position',[0.1,0.1,0.5,0.5],'Curvature',[1,1]) Рис. 7.10. Квадраты с разными радиусами закругления Контуры прямоугольника могут быть построены линиями любого допустимого типа, хотя в районе закругления стиль линии строго не соблюдается (рис. 7.И). В примере 7.11 использован любопытный прием — значение свойства кривизны задано не вектором, а скалярной величиной. Однако в этом случае кривизна по обеим осям считается одинаковой. ^"П|$Ш£§Щ'||^^ й:углами , ;^ ,$ч ^-^^2^Щ » rectangle('Position',[0.5,0.5,3,1], ... • ' Curvature' ,0.4,' LineWidth', 2, • LineStyle',' — ') » xlim([0,4]) » ylim([0,2]) » daspect([1,1,1])
290 Глава 7 Значение свойства Edgecoior задает цвет контура. С помощью свойства FaceCoior можно закрасить внутренность графического объекта (пример 7.12, рис. 7.12). 2 15 1 0.5 г' - - J?K гШН> г 1 \ ч i#%~*U, V I 1 / „У О 0.5 . 1 1.5 2.5 3.5 Рис. 7.11. Прямоугольник со штриховым контуром .;ПрИмёр;7.12.;[1Ь<^^ .-"?•■■ "-^Ш" » rectangle('Position', [1,2,5,10],'Curvature',[1,1], ... 'FaceCoior', 'г') 12 Г 10. Л У 1- V-t * ' зйИчЯ ■Л 1 .-* ■ ft" 1 ч 2 ..-^- э Л0 ■ ,.1| --...>(!; 1Ь_. 1. ■: Г-'. :: -■ S ♦ i, Т1 v ■; 6-: Рис. 7.12. Закрашенный эллипс
Иерархия графических объектов и их свойства 291 7.6. Объект Text Функция text предназначена для формирования надписей (объектов Text) в поле текущего объекта Axes. В простейшем случае обращение к ней напоминает вызов процедуры outtextxy в графическом пакете Borland Graphics Interface: » h_Txt=text(0.5,0.5,'Hello, World!'); Два первых аргумента в этом обращении представлены координатами точки привязки текста. Третий аргумент определяет воспроизводимый текст. Результат этого обращения представлен на рис. 7.13. 1 ав D.6 D.4 0,2 0 - 1. °-2 D.4 Hello. Worldl .'..0.6 0.8 .. 1 Рис. 7.13. Текст в центре поля осей Положение надписи относительно точки привязки регулируется значениями двух СВОЙСТВ Объекта — Horizontal Alignment (горизонтальный ПрИЖИМ) И verticaiAiignment (вертикальный прижим). Допустимым значением первого свойства является одна из строк — left (к левой границе), center (по центру), right (к правой границе). По умолчанию действует левый прижим. Если вокруг надписи построить габаритный прямоугольник, то его положение относительно координаты х точки привязки в зависимости от значения левого прижима показано на рис. 7.14. Координаты левого нижнего угла габаритного прямоугольника, его ширина и высота составляют вектор значений свойства Extent. Допустимым значением вертикального прижима является одна из строк — middle (по центру), baseline (на линии строки), top (по верхней границе), bottom (по нижней границе), cap (под линией строки). Положение габаритного прямоугольника относительно координаты у точки привязки в зависимости от вертикального прижима показано на рис. 7.15. По умолчанию действует прижим по центру. I
292 Глава 7 Left Center Right Рис. 7.14. Влияние горизонтального прижима -МккНе- Ragplirw Bottom "Cap" Top Рис. 7.15. Влияние вертикального прижима Если надпись должна сопровождать изображение трехмерного объекта, то координаты точки привязки содержат еще одну переменную z: » h_Txt=text(х,у,z,'подпись'); Кроме координат точки привязки и текста надписи среди параметров функции text могут присутствовать пары "свойство — значение", определяющие те или иные характеристики объекта Text. В примере 7.13 приведен полный список свойств объекта, представленного на рис. 7.13. » get(h_Txt) BackgroundColor = none- Color = [0 0 0] EdgeColor = none EraseMode = normal Editing = off Extent = [0.493151 0.444444 0.260274 0.1] FontAngle = normal . FontName = Helvetica FontSize = [10] FontUnits = points FpntWeight = normal
Иерархия графических объектов и их свойства 293 HorizontalAlignment = left LineStyle = - LineWidth = [0.5] Margin = [2] Position = [0.5 0.5 0] Rotation = [0] String = Hello, World! Units = data Interpreter = tex VerticalAlignment = middle BeingDeleted = off ButtonDownFcn = Children = [] Clipping = off CreateFcn = DeleteFcn = BusyAction = queue HandleVisibility = on HitTest = on Interruptible = on Parent = [102.007] Selected = off SelectionHighlight = on Tag = Type = text UIContextMenu = [] UserData = [] Visible = on Координаты (x, y, z) и воспроизводимый текст могут быть представлены массивами одинаковой размерности. Это означает, что функция text создаст несколько объектов, каждый из которых будет иметь свою точку привязки (xj., у±, zj.). Компоненты надписей при этом могут быть заданы разными способами — либо в виде массива ячеек, каждый элемент которого предсгавлен строкой, либо в виде массива строк одинаковой длины, либо в виде вектора-строки, в котором надписи разделены символом |. Обращение вида: text(х,у,z, 'string')
294 Глава 7 эквивалентно вызову функции text со следующим набором свойств: text('XData',x, 'YData',y, 'ZData',z, 'string', 'текст') Наряду с обычными символами отображаемая строка может содержать специальные комбинации, принятые в редакторе ТеХ и позволяющие воспроизводить обозначения, характерные для математических формул (табл. 7.4). Таблица 7.4 Строка ТеХ \alpha \beta \gamma \delta \epsilon \zeta \eta \theta Wartheta \iota \kappa \lambda \mu \nu \xi \pi \rho \sigma \varsigma \tau \equiv Mm \otimes 1 Символ ! a IP 1 Y ! s 1 E ! с \r\\ \ e 1 ■& i i ! к ! * j n 1 V u ■ rc 1 p ! о ! ? 1 T [ = ! 3 I ® Строка ТеХ \upsilon \phi \chi \psi \omega \Gamma Delta \Theta \Lambda \Xi \Pi \Sigma \Upsilon \Phi \Psi \Omega \forall \exists \ni \cong \approx \Re \oplus 1 Символ ! u i * [x ! v i to i г 1 A ; в ! л 1 E ! П ! 2 ! Y | Ф 1 ^ j £1 i v | 3 j э j = I = ! я ! © Строка ТеХ \sim \leq \infty \clubsuit \diamondsuit \heartsuit \spadesuit Meftrightarrow Meftarrow \uparrow \rightarrow \downarrow \circ \pm \geq \propto \partial \bullet \div \neq \aleph \wp \oslash j Символ | - ! < : 0° i * I ♦ ! * ; A 1 <-> i <— ! т ! —> | 1 | о ! + 1 > • oc !й \ • 1 + 1 / 1 N ! p 1 0
Иерархия графических объектов и их свойства 295 Таблица 7.4 (окончание) Строка ТеХ I Символ \сар I п \supset 1 з \int | J \rfloor j J \ffloor I L \perp ! 1 Wedge j л \rceil j 1 Wee ! v Mangle j < Строка ТеХ ! Символ \cup | u \subseteq j с \in j iE \lceil | Г \cdot \neg 1 -, \times 1 x \surd j V \varpi 1 w \rangle 1 ) Строка ТеХ ; Символ \supseteq ] з \subset j с \o ! 0 \nabla j V \ldots j ... \prime j ' \0 j 0 \tnid I | \copyright j © Используя соглашения ТеХ (пример 7.14), можно дублировать значения таких свойств объекта Text, как имя шрифта (FontName), высоту символов (FontSize), угол наклона СИМВОЛОВ (FontAngle): П \fontname{HMH_mpM$Ta}; D \fontsizelвысота символов} в единицах, установленных в свойстве FontUnits; □ \bf — жирный шрифт (bold); П \гга — Прямой шрифт (normal); □ \it — наклонный шрифт (italic). \ Пример 7.14. Использование-йотации ТёК^^Щ0Ш^$^т"^^^:^;:.уШ^:\ » х = 0:pi/20:2*pi; » plot (х, sin (х) ) » text(pi,0,' Ueftarrow sin(\pi)','FontSize',18) Результат работы этого фрагмента приведен на рис. 7.16. Еще один пример воспроизведения формулы функции комплексного переменного приведен на рис. 7.17. Запись самой формулы по правилам ТеХ имеет вид, представленный в примере 7.15.
296 Глава 7 ,~, Р.5 0 -0.5 1[ / / ) 1 \ \ N 2 Э - Sin(7l) / \/ ' 4 5 6" г Рис. 7.16. Подпись графика в точке (л, 0) 1 D.B 0.6 0.4 0.2 0 ( е?"1 = cos(ax) + i sin(Kn) i i i ] 0.2 0.4 0.6" , 0.8 Т;- *£ 1 Рис. 7.17. Пример вывода формулы I Пример 7.15. Воспроизведение формулы в рисункеЛ-Ч1^|ф|%ч^§^833^!^^,^''-'^р text(0.2,0.8,'e'MiNomegaXtau} = cos(\omega\tau) + i sin(\omega\tau)') Разрешением или запретом на использование такого рода записей управляет свойство interpreter, которое может принимать одно из двух значений: tex или попе. По умолчанию нотация ТеХ разрешена. Свойство Position для объекта типа Text немного отличается от аналогичного свойства других [рафических объектов. Компонентами его вектора являются только координаты точки привязки (х, у, г). Габариты подписи, точнее окаймляюшего ее прямоугольника, задаются значением компонентов свойства Extent. Любая подпись может быть повернута на заданный угол, если ее свойству Rotation присвоено значение этого угла в градусах (пример 7.16).
Иерархия графических объектов и их свойства 297 ШШШШШШШШШШШШВШШт » text(.1,.1,'Hello, World!','Rotation',45) Результат поворота представлен на рис. 7.18. ' ? 1 . о.е ь й* - ■; 0.2 ■ *Л • г ) 0.'2 ■ ■i 0.4 0.6 -;-~Л 'А 0.8" & 1 1 .-J Рис. 7.18. Поворот текста на 45е С помощью свойства Editing можно разрешить режим редактирования текста, отображенного в поле осей. В момент появления подписи, для которой разрешен режим редактирования (Editing=on), в ее начале мигает текстовый курсор, и пользователь может выполнить обычную для текстов правку, например, заменить слово Hello на слово привет (рис. 7.19). По умолчанию режим редактирования запрещен: » text{.1,.5,'Hello, Wcrld!','Editing','on')' 1 0.8 0.6 ■•0.4 0!2 °t ШИ World! i ■у 0.2 ■ "■ 0.A : ■ 0.6 0.B 1 Рис. 7.19. Редактирование текста
298 Глава 7 Включив свойство selected (по умолчанию selected=off), мы сразу получим выделенный текст (рис. 7.20): » text(.1,.5,"Hello, World!','Selected1,'on') Эффект такого же выделения может быть достигнут и с помощью кнопок на панели инструментов управления графиком. Однако основный смысл этого свойства — другой. С его помощью программа обработки некоторого события может узнать, выделил ли пользователь тот или иной текст в графическом окне. -> Figure 1 File Edit View Insert Tools Desktop Window Help d с» a m I k 1Q. a. & ® | -#; d в | и □ 1 0.8 0.6 0.4 0.2 0 ( - _, ■__ *Hello.World!" ш ■ ■ 3 , 0.2 0.4 0.6 0.8 ' A HDD ii is" 1 . Рис. 7.20. Программное выделение текста 7.7. Объект Image Графический объект типа image предназначен для воспроизведения растровых изображений, которые либо считываются из графических файлов, либо специальным образом формируются в оперативной памяти. Растровые изображения состоят из окрашенных прямоугольных элементов, заполняющих в поле осей графического окна область размером mxn элементов. В частном случае роль таких прямоугольных элементов изображения могут играть пикселы экрана. Данные о кодах цветности каждого элемента изображения составляют матрицу, которая представляет свойство cData объекта image. MATLAB предоставляет возможность работы с изображениями трех типов.
Иерархия графических объектов и их свойства 299 Первый из них составляют так называемые RGB-объекты, описываемые в формате truecoior. Для них матрица CData имеет размерность тхпхз и каждому элементу изображения с координатами (i, j) в матрице цветности соответствует тройка вещественных числовых значений в диапазоне от о до 1, определяющая интенсивность составляющих компонентов: □ элемент с индексами (i, j, l) — интенсивность красного цвета; П элемент с индексами (i, j, 2) — интенсивность зеленого цвета; О элемент с индексами (i, j, з) — интенсивность синего цвета. В форматах графических файлов, используемых в среде Windows, аналогичные RGB-компоненты пикселов хранятся как 8- или 16-битные целые числа. Второй тип графических изображений составляют так называемые индексированные (indexed) объекты, у которых матрица CData имеет размерность mXn и каждый ее элемент представляет собой целое число в диапазоне от о до 255 или от о до 65 535. Это число рассматривается как индекс в массиве палитры (coiormap), который ассоциирован с текущим графическим окном. Массив палитры, в свою очередь, состоит из числовых троек в диапазоне [о, i|, характеризующих интенсивность RGB-компонентов. К такому косвенному способу представления цвета пикселов прибегают при кодировании растровых изображений в формате BMP, когда на каждый пиксел отводится 1, 4, 8 или 16 битов. Индексированный подход позволяет более экономно закодировать изображение при относительно небольшом количестве используемых цветовых оттенков. К третьему типу относятся полутоновые монохромные изображения, в которых элемент двухмерной матрицы CData определяет интенсивность цвета в так называемой серой шкале (grayscale). Этот масштабный коэффициент в массиве CData также приведен к диапазону [о, i], хотя в графических файлах Windows для хранения оттенков серого используются 8- или 16-битные целые числа. Таким образом, если массив cmta — трехмерный, то соответствующее графическое изображение представлено в формате truecoior. А для того чтобы отличать индексированные изображения от полутоновых, у объекта image предусмотрено свойство CDataMapping. По умолчанию его значением является строка direct, соответствующая типу изображения coiormap. Вторым значением свойства CDataMapping является строка scaled, соответствующая изображению в серых тонах. Чтобы подчеркнуть разницу между пикселами и элементами изображения, создадим индексированный объект типа image размерности 3x4 (пример 7.17).
300 Глава 7 12 3 4 .5678 9 10 11 12 » h = image(X); % формирование изображения размерности 3x4 » colormap(colorcube(12)) % формирование цветовой палитры Функция coiorcube(n) по некоторому закону формирует п цветовых троек, которые используются в качестве цветовой палитры для индексных изображений нашего приложения. Результат выполнения указанного фрагмента приведен на рис. 7.21. 1 0.5 1 .. ^. % ,- Г i ' 'г» 2-Я & 2.5 **? 3 3i5 J '.■№, 1 1.5 if &«* 2 mr - И' '*; с as.',: 4t. 4l№ 4S.T" P 25 3 •1 j. :'i *»* '"' г .■; i 4 3.5 4 : ' : _. «"'" Рис. 7.21. Индексированное изображение размером 3x4 Познакомимся с наиболее важными свойствами созданного объекта (пример 7.18).
Иерархия графических объектов и их свойства 301 » get(h) AlphaData = [1] AlphaDataMapping = none CData = [ (3 by 3) double array] CDataMapping = direct EraseMode = normal XData = [1 4] YData = [1 3] BeingDeleted = off ButtonDownFcn = Children = [] Clipping = on Create.Fcn = DeleteFcn = BusyAction = queue HandleVisibility = on HitTest = on Interruptible = on Parent = [101.001] Selected = off SelectionHighlight = on Tag = Type = image UICpntextMenu = [] UserData = [] Visible = on Свойства AlphaData и AiphaDataMapping, связанные с прозрачностью элементов изображения, в нашем примере не используются. Значения упоминавшегося выше свойства CData в нашем случае совладают с элементами массива х, использованного при создании объекта: » get(h,'CData') ans = 1 5 9 2 6 10 3 7 11 4 8 12
302 Глава 7 Свойство CDataMapping свидетельствует о том, что наше изображение строится на базе индексированных данных (CDataMapping=direct). Режим Eras.eMode=normal означает, что при выводе изображения предшествующее содержимое поля осей стирается. Если мы с помощью функции set изменим значение свойства CData, то перед выводом нового изображения прежнее изображение будет уничтожено. В том случае, когда планируется вывод последовательных кадров анимированного изображения, режим стирания приводит к дополнительным затратам времени и вместо плавного перехода от кадра к кадру вызывает дергание на экране. Для более плавного отображения динамических кадров предпочтительнее установить EraseMode=none. Значения свойств XData и YData определяют диапазоны изменения индексов по осям х и у. Для объекта размерности mXn значениями этих свойств по умолчанию являются интервалы XData=[i п] и YData=[i m]. Если по каким-то соображениям значения индексов необходимо сместить, то это можно сделать так, как представлено в примере 7.19. г_.^...„...:™.................:...„ [Пример 7.19. Смёще;нйе;Координат;изобрЩ^ » image(X,'XData', [-1 2],'YData',[2 4]); » colormaptcolorcube(12)) Само изображение при этом не изменится, поменяется только оцифровка координатных осей (рис. 7.22). 1.5 2 2:5 ■а* .э.6-"" \к. А л, ** '$* , 1 . ■ i;. . -а.. . -1 . .feji,. i -0.6 'h D ■' :.4 .i- -0.5 ' .:■■ 1 "V ..';■ .•■■<. ~ - 'l '"-1S 2 r- : 2.5 Рис. 7.22. Смещение координат изображения
Иерархия графических объектов и их свойства 303 Вообще говоря, созданный нами графический объект действительно состоит из 12 цветных точек, расположенных в 3 ряда. Однако при его отображении произошло масштабирование под фактические размеры области осей, и каждая точка превратилась в большой цветной прямоугольник. Как правило, программы отображают рисунки, считываемые из графических файлов. Познакомимся более подробно с технологией чтения и визуализации изображения на примере летательного аппарата НАСА, которое хранится в каталоге MALAB7\tooIbox\aeroblks\aerodemos под именем aeroblk_HL20pic.jpg. Чтобы не возиться с таким длинным именем, скопируем его в рабочий каталог \work под именем aero.jpg. Во-первых, получим информацию об этом рисунке с помощью функции imfinfo (пример 7.20). чПрймёр .20. Свойства фай а с изображением "..'... , "'.. L'\vW' » imfinfo ('aero.jpg') ans = Filename: 'aero.jpg' FileModDate: '28-Mar-2002 21:40:54' FileSize: 17774 ■Format: 'jpg' FormatVefsion: '' Width: 319 Height: 396 BitDepth: 24 ColorType: 'truecolor' FormatSignature: '* Comment: {} Из полученной информации следует, что размер рисунка в пикселах — 319x396, и на код цветности каждого пиксела отведено 24 бита (по 8 битов на каждую цветовую составляющую, и это соответствует формату truecolor). Прочитаем содержимое указанного файла в массив а и создадим на его базе графический объект типа image: » A=imread('aero, jpg'); >>. h_rmg=±mage (A.) ; Созданное изображение вписывается в размеры графического окна, которые по умолчанию MATLAB устанавливает при отсутствии дополнительных указаний. Из рис. 7.23 видно, что пропорции рисунка по осям хну подверглись искажению.
304 Глава 7 Рис. 7.23. Изображение с нарушенными пропорциями Для приведения в соответствие шагов по осям х и у достаточно выполнить команду: » axis image Результат не замедлит сказаться. Действие команды axis image эквивалентно установке свойства DataAspectRatio ДЛЯ объекта Axes В [1 1 1]. По маркировке осей (рис. 7.24) видно, что шаги по осям стали одинаковыми. Теперь не мешает привести размеры графического окна в соответствие с пропорциями изображения: » A=imread('aero.jpg'); >> [m n k]=size(A) m = 396 n = 319 k = 3
Иерархия графических объектов и их свойства 305 » figure('Units',"pixels','Position',[100 100 n m]) » Image(A); •> Figure 1 File ^^b^o&O^yi^m,^ ___^_ DSHanl^^^SiC'Dgl -■-'"- -,- . ■■■'-.■ ■" -.--: ■%■■ 1 ..*•„-,**.. >«#-** ~J* ,£-:.£ iTS-ЧГ ^-1-1-- -' ^1&У*/&,-1& „ '. ■ ■■ T*" "; 5Q- '\ " r-v Ю0 к JW«4- ' ..¾^ . '" • *• ~Ъ "f^ W 150 ' ^¾ ■! ,-Л»- ,--200 ■.... ^ ; ■ v- ^ ^**N"V ■ " ,.#:k Set -«Г ■ -- J" 350^ .,.^ 'W4* .., #¢.¾^.¾¾^ saostf - N> 5=^ .¾¾1 ,ii Л :'■ 50 ■ 100 4* f. %: rap "ii-. M Щ $ ?■ 150 ,.-.\" Г--ь' ".*■ * : *• ™ f . / '""-/ :- л i --- "4. л "'J. . v .4 %. " Ж W * V T ■ Jb,- ■ c; % ",-.%-4 - ?..-*■* ' ■ 200 250 300 ■ . a. ВПП --■■ . Л. . , ■:■. " ,-' ■■-■ :.-.. 1 " 4?;V я s ■ >*, '*\*$ " .•-r^v.f l ■' ■ i - й;>- «^'^Г Щ, jKff.* к-' ^: ~ Рис. 7.24. Изображение с восстановленными пропорциями Результат работы этого фрагмента приведен на рис. 7.25. И, наконец, последний штрих — расширение плошали осей на всю рабочую область графического окна: » set(дса,'Position',[0 0 1 1]) Последнее изображение, заполняющее поверхность графического окна, приведено на рис. 7.26. А теперь познакомимся более подробно с функциями, используемыми при создании и визуализации изображений. Функция imread применяется для считывания матрицы цветности изображения из графических файлов разных форматов. Пример чтения изображения типа truecolor мы уже продемонстрировали. Однако возможен и несколько иной вариант чтения RGB-изображений: » А = imread('aero','jpg')
306 Глава 7 •> Figure 2 НПО File Edi Viev inset Tool Deskfc Wlndo Helf -»■ ___ __. _.. ^.-^ ^ _ „ _^„__ ,-^¾¾¾¾¾¾¾¾^^ 50 S^ 100. '. 200 250 '' ,,¾ 300 350 к _ :,.., .^ v. ' £■ ■: ' ,t ™ (Я t -Двгг^"'! ч»*£ lit* - tk 4- V 1 ¥~ 100 200 300 Рис. 7.25. Размер окна приведен к размерам рисунка »Л Figure 2 ИПП Fife Edl Vlev Ipsa Ipol Desktc Wlndo Helf * D &UB\ k |«.ein®i«J!D " ^.: ..-...- .■■ ■* 1 |t «-V: u,. ' - - A a * e- i 1 *V Рис. 7.26. Последний штрих При считывании индексированного изображения функция imread возвращает два параметра — массив индексов (х) и ассоциированную палитру цветов (шар): » [X,map]=imread{'name','fmt'); Второй аргумент в этом обращении задает расширение графического файла, если оно в явном виде не указано в имени файла ('name"). Считанный таким образом индексированный рисунок воспроизводится в поле осей следующим образом: » image(X); » coiormap(map) Функция coiormap (map) приписывает цветовую палитру текущему графическому окну. Матрица тар может иметь сколько угодно строк, но в каждой из них должны находиться только три вещественных числа из диапазона [о, \\. Они воспринимаются как значения RGB-компонентов цвета, соответствующие индексу строки матрицы reap. Обращение к функции coiormap без параметров возвращает значения текущей палитры фафического окна. По умолчанию каждое фафическое окно снабжается палитрой, унаследованной от корневого объекта Root. Она содержит 64 строки с числовыми компонен-
Иерархия графических объектов и их свойства 307 тами, приведенными в табл. 7.5. Из этой таблицы становится понятно, почему изображение, приведенное на рис. 7.21, до смены палитры появляется в синих тонах. Первые 12 цветовых оттенков палитры по умолчанию содержат преимущественно градации синего. Таблица 7.5 № 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 R 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0,0625 ; G ! о ! о ! о I 0 | 0 I ° ] 0 | о I 0,0625 ! 0,1250 | 0,1875 | 0,2500 | 0,3125 I 0,3750 ! 0,4375 | 0,5000 | 0,5625 | 0,6250 | 0,6875 | 0,7500 | 0,8125 | 0,8750 | 0,9375 | 1,0000 | 1,0000 ! В | 0,5625 ] 0,6250 I 0,6875 ! 0,7500 | 0,8125 | 0,8750 | 0,9375 | 1,0000 | 1,0000 | 1,0000 ! 1,0000 ; 1,0000 ! 1,оооо I 1,0000 ! 1,оооо | 1,0000 | 1,0000 ! 1,0000 ; 1,0000 ! 1,оооо | 1,0000 I 1,0000 j 1,0000 ! 1,0000 | 0,9375 № 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ! R | 0.1250 ) 0,1875 ! 0,2500 | 0,3125 | 0,3750 I 0.4375 ) 0,5000 | 0,5625 | 0.6250 | 0,6875 | 0,7500 | 0,8125 | 0,8750 I 0,9375 | 1,0000 | 1,0000 | 1,0000 | 1,0000 ! 1,0000 I 1,0000 | 1,0000 | 1,0000 | 1,0000 | 1,0000 I 1,0000 ! G | 1,0000 | 1,0000 I 1,0000 | 1,0000 | 1,0000 I 1,0000 | 1,0000 I 1,0000 ! 1,0000 | 1,0000 | 1,0000 | 1,0000 j 1,0000 | 1,0000 | 1,0000 I 0,9375 | 0,8750 | 0,8125 | 0,7500 ! 0,6875 | 0,6250 | 0,5625 I 0,5000 j 0,4375 | 0,3750 \ в | 0,8750 I 0,8125 | 0,7500 I 0,6875 | 0,6250 | 0,5625 I 0,5000 j 0,4375 ! 0,3750 | 0,3125 | 0,2500 | 0,1875 ! 0,1250 | 0,0625 j 0 | 0 ! о ! о ! о ! ° | 0 I ° | 0 I ° ! о
308 Глава 7 Таблица 7.5 (окончание) № ! R | G | В 51 I 1,0000 | 0,3125 | 0 52 | 1,0000 | 0,2500 | 0 53 | 1,0000 | 0,1875 | 0 54 | 1,0000 | 0,1250 j 0 55 j 1,0000 | 0,0625 ; 0 56 I 1,0000 | 0 | 0 57 | 0,9375 ; 0 ; 0 № | R | G ! В 58 j 0,8750 ! 0 | 0 59 j 0,8125 | 0 JO 60 j 0,7500 ; 0 | 0 61 j 0,6875 JO ;0 62 j 0,6250 JO JO 63 ; 0,5625 | 0 ; 0 64 j 0,5000 JO JO Аргументами функции image кроме матрицы цветности могут быть два двухэлементных вектора х и у, которые подменяют диапазоны маркировки осей изображения: » image {х, у, С) Нечто подобное мы уже демонстрировали в самом первом примере этого раздела: » image{X,'XData',[-1 2],'YData',[2 4]); Таким же образом могут быть изменены и любые другие свойства при создании объекта типа image: » h_Img=image('свойство1',значение1,'свойстве^',значение2,...); Список форматов графических файлов, содержимое которых может быть извлечено с помощью функции imread, приведен в табл. 7.6. На самом деле за каждым из этих форматов скрывается довольно много вариантов, отличающихся глубиной палитры (т. е. количеством битов на код цветности пиксела), использованием того или иного метода сжатия данных, количеством изображений, закодированных в одном файле. Поэтому функция imread допускает несколько частных форматов обращения для конкретных графических файлов. Узнать об этих деталях вы сможете, обратившись за справкой ПО функции imread. Таблица 7.6 Формат Тип графического файла ' bmp' Windows Bitmap (BMP) ' cur' Windows Cursor resources (CUR) ' gif' Graphics Interchange Format (GIF) ' hdf' Hierarchical Data Format (HDF)
Иерархия графических объектов и их свойства 309 Таблица 7.6 (окончание) Формат Тип графического файла ' ico' Windows Icon resources (ICO) 'jpg' I 'jpeg' Joint Photographic Experts Group (JPEG) ' pbm' Portable Bitmap (PBM) ' pcx' Windows Paintbrush (PCX) ' pgm' Portable Graymap (PGM) ' png' Portable Network Graphics (PNG) ' pnm' Portable Anymap (PNM) — обобщенное расширение одного из форматов: Portable Bitmap (PBM), Portable Graymap (PGM) и Portable Pixel Map (PPM) ' ppm' Portable Pixmap (PPM) ' ras' Sun Raster (RAS) •tif | 'tiff Tagged Image File Format (TIFF) ' xwd ■ X Windows Dump (XWD) В "прозрачности" пикселов изображения и связанных с ней свойствах AlphaData и AlphaDataMapping нам поможет разобраться примитивная схема считывания и визуализации значков. Для файлов с расширением ico функция imread возвращает 3 аргумента: [X,map,Alpha] =dmread( 'matlab.ico') ; Как правило, значки представлены небольшими растровыми рисунками размером 32x32 пиксела. Значки, расположенные на вашем рабочем столе, далеко не всегда имеют форму квадрата. Это означает, что часть пикселов рисунка обязана быть "прозрачной", из-под них должны просвечивать пикселы того фона, на который накладывается изображение значка. Массив Alpha, возвращаемый функцией imread, имеет такую же размерность, как и индексный массив х, и состоит он из нулей и единиц. Единица, расположенная в позиции (i, j) изображения значка, означает, что соответствующий пиксел должен быть прозрачным. В примере считывания фирменного значка MATLAB возвращаемые массивы имеют размерности, приведенные в примере 7.21. |Пример.:7.21. Изображение.с прозрачными областями^г^Х>^Ш'ь^^^л^с1^^ » size(X) ans = .% размерность массива индексов 32 32
310 Глава 7 » size(map) ans = % размерность палитры 256 3 » size(Alpha) ans = % размерность матрицы "прозрачности" 32 32 Обратите внимание на тип возвращаемых данных: » whos Name Size Bytes Class Alpha 32x32 1024 logical array X 32x32 1024 uintS array map 256x3 6144 double array Из внешнего вида фирменного знака MATLAB следует, что левый верхний пиксел квадрата, занятого рисунком, должен быть прозрачным. Об этом же свидетельствует и значение элемента Alpha (i, i): » Alpha(1,1) ans = 1 Однако индекс этого пиксела и соответствующая тройка в палитре цветов указывают на то, что эта точка — черная. » Х(1,1) ans = 0 >> mapd,:) ans = 0 0 0 Поэтому, если построить объект типа image без каких-то дополнительных ухищрений, то все пикселы изображения, не принадлежащие узору значка, окажутся черными: » h_Img=image (X); col.ormap (map) Результат лобового подхода представлен на рис. 7.27. А теперь попробуем модифицировать процесс создания объекта типа image следующим образом. Во-первых, добавим к считанной палитре новую строку с компонентами белого цвета: » mapl = [map; 1 1 1];
Иерархия графических объектов и их свойства 311 Рис. 7.27. Отображение значка без учета признаков прозрачности Во-вторых, создадим копию индексного массива, пока заполненную ссылками на строку белого цвета: >> XI = ones(size(X))*(length(mapl) - 1); Теперь перепишем все индексы всех непрозрачных пикселов из массива х в массив xi: » XI(Alpha = 0} = X(Alpha = 0); Наконец, построим объект типа image по сформированным данным, не забыв предварительно преобразовать массив xi из типа double к типу uinte: » image(uintS(XI)); GQlormdp(mapl) Окончательный результат, представленный на рис. 7.28, свидетельствует о том. что все прозрачные пикселы значка теперь окрашены в белый цвет. С помощью немного более сложных манипуляций можно было бы вместо белых точек проявлять цвет точек графического окна, на которые накладываются прозрачные пикселы значка. В самом общем случае матрица прозрачности AlphaData имеет такую же размерносгь, как и матрица CData. Ее элементами могут быть либо вещественные числа типа double, либо целые числа типа uinte. В зависимости от значения свойства AlphaDataMapping элементы матрицы AlphaData расшифровываются одним из трех способов: П как коэффициенты прозрачности соответствующих пикселов изображения (AlphaDataMapping=none); 11 Зак. 85S
312 Глава 7 П как индексы в текущем массиве Alphamap, приписанном графическому окну (AlphaDataMapping=direct); П как масштабирующие множители, с помощью которых вычисляются коэффициенты прозрачности в диапазоне от минимального до максимального значений, заданных СВОЙСТВОМ ALim (AlphaDataMapping=scaled). -Г е 10 15 20 25 30 •■ _ г 5 -ш- :> ■у- ч 1Г-" — ,?■ 10 15. 1-й. ' ,7- 1 *' ■■' Ч ш. ■Г .. 20 25 .- ■! .¾¾% _ .-.J' 30 Рис. 7.28. Изменение цвета прозрачных пикселов Функция imwrite, осуществляющая запись объекта типа image в графический файл, может оказаться полезной для преобразования одного графического формата в другой. Подобно функции imread, эта функция тоже допускает несколько форматов обращения, из которых мы приведем только два: imwrite(А,'пате','fmt') % запись изображения типа colormap imwrite (X,map, 'name',' frht') % запись индексированного изображения 7.8. Поиск объектов Обращение к функциям get и set для опроса или установки значений отдельных свойств объектов требует знания указателя на соответствуюший объект. Функции, создающие тот или иной графический объект, как правило, возвращают значение указателя на созданный объект. Но что делать, если мы забыли сохранить возвращаемое значение?
Иерархия графических объектов и их свойства 313 Для текущего графического окна (объекта типа Figure), текущего поля графика (объекта типа Axes) и объекта, выбранного в данный момент пользователем (объекта, генерирующего событие callback), можно воспользоваться системными функциями gcf, gca и gcbo соответственно. Но если нужный графический объект не принадлежит ни к одной из перечисленных категорий, то восстановлению его указателя поможет функция findobj. Для обращения к ней достаточно знать значение какого-либо свойства, характерного для искомой фигуры. Иногда перед обращением к функции findobj полезно узнать перечень объектов, среди которых имеет смысл производить поиск. Для формирования списка указателей объектов, порожденных графическим объектом с известным указателем h_obj, следует обратиться к функции findaii (пример 7.22). ; Пример 7:22; Получение сНиека указателей на ■в^.объекгы^^-^'щк^ u \ ":& ^ » х=0:0.1:2*pi; » plot(х,sin(х)) » h_All=findall{gca) h_All = 101.0020 3.0016 По количеству возвращенных значений можно догадаться, что в текущем поле графика созданы два графических объекта. Но что скрывается за каждым из возвращенных значений, тем более, что указателями являются вещественные числа, точные значения которых неизвестны? Попробуем опросить тип каждого из объектов (пример 7.23). |«nj>^R7>23;-9^^C-TMn^О^^в »*-^¾^^¾^¾^ -W; ^¾¾¾ >> get(h_All(l>,"Type') ans = axes » get(h_All(2),'Type') ans = line Теиерь-то мы можем воспользоваться функцией findobj: » hl=findobj'( 'Type', 'axes') hi = 101.0020
314 Глава 7 » h2=findobj('Type','line') h2 = 3.0016 А поскольку значения указателей попали в переменные hi и п2, то можно в полной мере воспользоваться услугами функций get или set. Вообще, в приведенном выше примере мы могли бы сузить область поиска и ограничиться единственным обращением к функции findobj: » hl=findobj(gca,'Type','axes') hi - 101.0020 Обращение к функции с единственным аргументом — указателем на графический объект — выдает вектор указателей на все дочерние объекты: » findobj(gca) ans = 101.0020 3.0016 Если в области поиска находится несколько объектов с заданным значением указанного свойства, то функция findobj возвращает вектор соответствующих указателей. Однако если функция не находит ни одного объекта с заданным свойством, то выдается сообщение об ошибке и возвращается пустой вектор.
Глава 8 Проектирование интерфейса Все Windows-приложения делятся на две категории — консольные и оконные. Консольные приложения, которые могут быть созданы в большинстве современных систем программирования (Visual C++, Borland C++ Builder (ВСВ), Delphi и др.), напоминают программы, функционирующие под управлением MS-DOS. В их распоряжении вся оперативная память и экран, режим работы которого максимально приближен к текстовому. Ввод данных консольного приложения может быть организован либо их чтением из файла, либо путем их набора на клавиатуре. В отличие от этого, оконные Windows-приложения включают одно или несколько окон, одновременно расположенных на экране, которые могут перемещаться, изменять свои размеры, пропадать и возникать вновь. Для ввода и вывода данных оконные приложения предлагают своеобразные "форточки" — редактируемые поля ввода/вывода символьной информации, выделенные в окнах прямоугольные области для отображения фафической информации. В окопных приложениях используется большой набор типовых компонентов, обеспечивающих диалоговое взаимодействие с пользователем — разнообразные кнопки, списки, индикаторы состояния различных процессов, полосы прокрутки, рамки и т. п. Система MATLAB тоже позволяет создавать оконные Windows-приложения, в которых широко представлены средства управления отображением 2D- и ЗО-объектов. Наряду с этим, MATLAB предлагает довольно скромный ассортимент компонентов, ориентированных на проектирование графического интерфейса. Тем не менее все эти компоненты оформлены в соответствии со стандартами Windows. Набор их свойств покрывает основные функциональные возможности аналогичных компонентов, предлагаемых современными системами визуального программирования. Полный перечень интерфейсных компонентов MATLAB приведен в табл. 8.1. Роль общепринятых форм — стандартных окон Windows. — в приложениях MATLAB выполняют графические объекты типа Figure. Конечно, в таких окнах не обязательно присутствие объекта, типа Axes, в котором строятся графические изображения.
316 Глава 8 Таблица 8.1 Наименование компонента Назначение Аналог в других системах программирования Push Button Toggle Button Radiobutton Checkbox Edit Text Static Text Slider Panel Button Group Простая кнопка Кнопка, фиксирующаяся в утопленном состоянии Переключатель — индикатор альтернативных вариантов Окошко — индикатор не- альтернативных вариантов Поле для вывода, ввода И редактирования текста Область для вывода текста (метка) Ползунок, полоса прокрутки Рамка, контейнер для интерфейсных компонентов Рамка для кнопок типа Radio Button И Toggle Button Visual Basic (VB) — CommandButton BCB, Delphi — Button Visual C++ — Push Button BCB, Delphi — SpeedButton VB —Option Box BCB, Delphi —RadioButton Visual C++— Radio Button VB — CheckBox BCB, Delphi — CheckBox Visual C++ — Check Box VB — TextBox BCB, Delphi - Edit Visual C++ — Edit Box VB — Label BCB, Delphi — Label, Static-Text Visual C++ — Static Text VB - HScrollBar, VScrollBar BCB, Delphi - ScrollBar Visual C++ — Horizontal или Vertical Scroll Bar VB — Frame BCB, Delphi — Frame, Panel, Group Box Visual C++ — нет аналога VB — Frame BCB, Delphi — Radio Group, Group Box Visual C++ — нет аналога
Проектирование интерфейса 317 Таблица 8.1 (окончание) Наименование Назначение компонента Аналог в других системах программирования Listbox Список, окно для отображения массива строк Popup Menu Всплывающее меню VB - ListBox ВСВ, Delphi — ListBox Visual C++ — List Box VB —Menu Editor BCB, Delphi — PopMenu Visual C++ — Menu Каждый интерфейсный элемент обладает заданным набором свойств, определяющих внешний вид и поведение компонента на стадии выполнения программы. Если большинство современных систем визуального программирования закрепляет за компонентами каждого класса индивидуальный набор свойств, то в пакете MATLAB любому интерфейсному элементу всегда приписано 41 свойство (табл. 8.2). Однако некоторые из них имеют смысл только для определенных элементов. Так, например, свойство ListBoxTop, определяющее индекс отображаемого элемента списка, для объекта типа Listbox представляет интерес, а для других интерфейсных элементов ничего не значит. Точно так же свойством, ориентированным только на обслуживание объектов типа slider, является минимальный и максимальный шаг перемещения ползунка при щелчках мышью (вектор значений свойства siiderstep). Свойства некоторых компонентов в пакете MATLAB трактуются не совсем обычно. Например, у выделенной кнопки типа Radio Button значение свойства value устанавливается в 1, а у невыделенной — в 0. Более подробно специфика использования каждого из интерфейсных компонентов и их свойств рассматривается ниже. Таблица 8.2 Свойство Назначение Допустимые значения BackgroundColor BeingDeleted BusyAction Цвет фона (по умолчанию — серый [0.753 0.753 0.753]) Признак возможности удаления (по умолчанию — off) Реакция на возникновение нового прерывания во время обработки текущего события (по умолчанию — queue) Вектор, задающий значения RGB-компонентов из диапазона от 0 до 1 on (разрешено), off (запрещено) queue (поставить в очередь), cancel (проигнорировать)
318 Глава 8 Таблица 8.2 (продолжение) Свойство Назначение Допустимые значения ButtonDownFcn Cdata Callback Children Clipping CreateFcn DeleteFcn Enable Extent Font'Angle FontName FontSize FontUnits FontWeight Указатель на функцию обработки события "Нажатие правой кнопки мыши" Массив для хранения изображения в формате truecolor, которое "наклеивается" на поверхность объекта Указатель на функцию — обработчик события Callback Массив указателей на потомков Признак отсечения при выходе изображения за границы объекта (по умолчанию — on) Указатель на функцию обработки события "Создание объекта" Указатель на функцию обработки события "Удаление объекта" Признак доступа к объекту (по умолчанию — on) Габаритный прямоугольник Признак наклона букв (по умолчанию — normal) Имя шрифта (по умолчанию — MS Sans Serif) Размер (высота) букв в установленных единицах (по умолчанию — 8 пунктов) Единицы измерения (по умолчанию-points) Толщина контура букв (по умолчанию — normal) on (включено), off (отключено) on (доступ разрешен), off (доступ запрещен) normal (прямой шрифт), italic (курсив), oblicue (наклонный) Список имен шрифтов, установленных в Windows inches (дюймы), centimeters (сантиметры), normalized, pixels (пикселы), points (пункты, 1 пункт = 1/72 дюйма) normal (нормальная), light (утонченная), derai (полужирная), bold (жирная)
Проектирование интерфейса 319 Таблица 8.2 (продолжение) Свойство Назначение Допустимые значения ForegroundColor Handle Visibility HitTest Horizontal Alignment Interruptible KeyPressFcn ListBoxTop Max Min Parent Position Selected Selection- Highlight Цвет рисования (по умолчанию - черный= [0.0 0.0 0.0]) Признак видимости указателя обработчика событий (по умолчанию — on) Признак разрешения поиска объекта по значению свойства (по умолчанию — on) Способ размещения надписи в поле объекта (по умолчанию — center) Признак разрешения прервать обработчик события (по умолчанию — on) Указатель на функцию обработки события "Нажата клавиша" в тот момент, когда компонент находился в фокусе Индекс строки разворачивающегося списка, которая отображена в верхнем окне (по умолчанию— о) Максимальное значение свойства Value (по умолчанию — Д.) Минимальное значение свойства Value (по умолчанию — 0) Указатель на родительский объект Позиция объекта — вектор, определяющий координаты нижнего левого угла объекта, его ширину и высоту в установленных единицах измерения Признак выбора объекта Признак повышенной яркости для выделения того или иного элемента в объекте (по умолчанию — on) Вектор значений RGB- компонентов on (доступен), off (не доступен) on (поиск разрешен), off (поиск запрещен) left (левый прижим), right (правый прижим), center (по центру) on (прерывание разрешено), off (прерывание запрещено) on (выбран), of f (не выбран) on (включен), off (выключен)
320 Глава 8 Таблица 8.2 (окончание) Свойство Назначение Допустимые значения SliderStep String Style Tag TooItipString Type UIContextMenu Units UserData Value Visible Вектор малых и больших перемещений ползунка Символьная строка, задающая надпись или значение, приписанное объекту Символьная строка с типом компонента (например, pushbutton, slider и др.) Символьная строка, в которой, как правило, хранится имя объекта (например, pushbuttonl, pushb.utton2 и Др.) Текст всплывающей подсказки (по умолчанию — пустая строка) Класс объекта Всплывающее меню, привязанное к данному объекту Единицы измерения линейных величин (ширины, высоты, длины и т. п.). Для объектов разного типа по умолчанию может быть разным Массив данных, ассоциированный пользователем с этим объектом (по умолчанию — пустой массив) Значение, характерное для данного объекта (например, величина смещения ползунка) Признак видимости объекта (по умолчанию — on) inches (дюймы), centimeters (сантиметры), normalized, pixels (пикселы), points (пункты) on (объект виден), off (объект невидим) Из состава компонентов в версии 7.0 исключена рамка Frame, которая заменена эквивалентным интерфейсным элементом Panel. Компоненты, размещенные на панели, считаются ее дочерними элементами и перемешаются вместе с панелью. По сравнению с рамкой Frame панель имеет немного меньше свойств, ио у нее появилась возможность изменять форму и ширину своих границ (свойства вогаегтуре и Borderwidth), а также местоположение
Проектирование интерфейса 321 надписи (свойство Tideposition). На рис. 8.1 и 8.2 отображены возможности по управлению этими свойствами. попе -beveledin- -etchedin- etchedout- "' beveledout line' '■* Рис. 8.1. Управление формой границ панели V iBfttop ., centertop '''- righttop iBftbottom centerbottom rightbottom TitlePosition none ** etchedin etchetiout beveledin ' "beveledout line BorderType Рис. 8.2. Варианты размещения подписи на панели 8.1. Динамическое создание интерфейсных элементов В системе MATLAB предусмотрены два способа организации интерфейса с пользователем. Первый из них условно назовем динамическим. Он заключается в том, что на стадии выполнения программы создаются те или иные графические объекты и их свойствам присваиваются соответствующие значения. Для создания любого интерфейсного компонента с заданными свойствами используется функция uicontroi, возвращающая указатель на формируемый компонент: hUIC = uicontroi([hFig,] 'Style','тип_компонента',... 1Свойство_1',Значение_1,... 'Свойство 2',Значение 2,... 'Свойство к'. Значение к);
322 Глава 8 Первый аргумент функции uicontroi не является обязательным, и если он отсутствует, то родителем (владельцем) создаваемого компонента является текущий графический объект. У существующего интерфейсного объекта можно изменить те или иные свойства с помощью функции set: set(UIC,'Свойство_1',Значение_1,... 'Свойство_2',Значение_2,... 'Свойство_к',Значение_к) Поясним сказанное на примере решения квадратного уравнения a ■ х2 + b ■ х + с = 0. Предположим, что нам хотелось бы видеть на форме главного приложения три окна для ввода коэффициентов уравнения, два окна для отображения значений найденных корней и кнопку для запуска алгоритма вычисления корней после ввода очередных значений коэффициентов (пример 8.1). В этом приложении очень полезным оказалось бы окно, воспроизводящее график функции у = a • х2 + b ■ х + с и визуально подтверждающее расположение найденных корней. Для контроля работы нашего будущего приложения предварительно проделаем все вычисления в командном окне. Набор коэффициентов (а, ь, с) целесообразно оформить в виде вектора, который понадобится как для вызова функции roots, вычисляющей корни полинома, так и для функции poiyval, вычисляющей значение полинома в заданной точке. Если результаты вычислений, выведенные по формату short, нам покажутся не очень удовлетворительными, то можно воспользоваться форматом long, чтобы увидеть значения корней и полинома с более высокой точностью. i Пример 8.1. Поиск решения квадратного уравнения '- г<: .••'. '. Л :; :...;. :.'....v.'. » а=1.5; » Ь=-2.4; » с=0.75; » р=[а b с]; » x=roots(р) X = 1.1742 р. 425.8 » poiyval(р,1.1742)
Проектирование интерфейса 323 ans = 3.8460е-005 » polyval(p,0.4258) ans = 3.8460е-005 » format long » x X = 1.17416573867739 0.42583426132261 »polyval(p, 1.17416573867739) ar.s = -4.329869796038111e-015 » polyvalfp, 0.42583426132261) ans = -4.551914400963142e-015 •> Figure 1 File Edit View Insert Tools Desktop Window Help ВПЕЗ 0.8 0.6 0.4 о.:2 о -0.2 п iJ <' \ л 1 ! \ \ j \ 1 \ 1 \1 1 и •/ ? /; 71 j / ; i 05 1:5 Рис. 8.3. График функции у = а-х2 + Ь-х + с
324 Глава 8 Теперь построим график нашей функции, положив в качестве граничных интервалов по оси X значения xmin=jnin(real(x(l)), real(х(2)))-0.5 И xmax=max[real(х(1)), real[х (2)))+0.5: » xrl=real{x(l)); » xr2=real(x(2)); » xmin=rrdn(xrl,xr2)-0.5,- » xmax=max(xrl,xr2)+0.5; » xx=xmin:0.1:xmax; » yy=polyval(p,xx); » plot(xx,yy) » grid on Окно приложения с графиком нашей функции приведено на рис. 8.3. Любые попытки расширить созданное окно, чтобы освободить пространство для предполагаемых полей ввода и кнопки, ни к чему не приведут. При изменении размеров фигуры график функции автоматически подстраивается под новые габариты. Поэтому придется принудительно задавать параметры окна, поля графика и всех интерфейсных компонентов на стадии выполнения программы. Предварительный дизайн формы можно провести на миллиметровке и не забыть после этого перевести миллиметры в пикселы (коэффициент пересчета для разных мониторов и установленного разрешения может оказаться разным). Числовые данные, которыми мы воспользовались для построения макета формы (рис. 8.4), хранятся в файле roots2.m (пример 8.2). Пример 8;2> Функция\х£бЬё?ЩЩг ' '••Ш^^ФЩк f - : • ".- " Щ h.....i ?....\v..v#..w.vi.,..:.....!T...i. . ..' .-.1 ,.....*.... .n.v.' л"..* . ... . ...... . ,t\.t.t ,V.-;.i . ni.'lh'u i :.'л . . i. .1 . .....v ..>... it -Gil . ...:} function roots2 % глобальные переменные global hFig hAxes hBtn global hTxta hTxtb hTxtc hTxtxl hTxtx2 global hEda hEdb hEdc hEdxl hEdx2 hfig=figure('Position',150,50,480,300]) ; hAxes=axes; set(hAxes,'Unit','pixels','Position',[30,70,280,220]) hTxta=uicontrol(hFig,'Style','text','String','a=',... •Position',[340,253,30,21],'BackgroundColor',[1 1 1]); hTxtb=uicontrol{hFig,'Style','text','String■,'b= *,... •Position',[340,218,30,211,'BackgroundColor',[1 1 1]);
Проектирование интерфейса 325 hTxtc=uicontrol(hFig,'Style','text','String','c=', . . . 'Position',[340,188,30,21],'BackgroundColor',[1 11]); hTxtxl=uicontrol(hFig,'Style','text','string','xl=',... 'Position',[340,113,30,21],'BackgroundColor',[1 1 1]) ; hTxtx2=uicontrol(hFig,'Style','text','String','x2=',... 'Position', [340,78,30,21], 'BackgroundColor', [1 1 1].) ; hEda=uicontrol(hFig,'Style','edit','Position',[380,250,100,25], 'BackgroundColor',[1 1 1],'HorizontalAlignment','left') hEdb=uicontrol(hFig,'Style','edit','Position', [380,215,100,25], •BackgroundColor',[1 1 1],'HorizontalAlignment','left'> hEdc=uicontrol(hFig,'Style','edit','Position',[380,185,100,25], 'BackgroundColor',[1 1 1],'HorizontalAlignment','left') hEdxl=uicontrol(hFig,'Style','edit','Position', [380,110,100 'BackgroundColor',[1 1 1],'HorizontalAlignment','left') hEdx2=uicontrol(hFig,'Style','edit','Position', [380,75,100,25], 'BackgroundColor',[1 1 1],'HorizontalAlignment','left') hBtn=uicontrol(hFig,'Style','pushbutton','String','Решение', •Position',[340,150,140,25],'Callback','roots3'); 25], •> Figure 1 НПО File Edit View Insert jrools Desktep Window 'Helpjf ... 0.8- .0.6 0.4 0.2' 0 ■!_-■= ЗД5- -■.. & *° -¾ b= <; c= i .-*K»v № ■ ■■• ■$-• Xl= Ui. ■V* x2= ]ит,- с* ■' * ;:. ■ 1 г •*. 1 | ,КС№Й£Ч- Решение | | 1 ■0.2 0:4 0.6: 0.8 Рис. 8.4. Эскиз окна предполагаемого приложения Прокомментируем содержимое файла roots2.m. Глобальные переменные, описанные в строках 3—5, предназначены для хранения указателей на динамически создаваемые объекты: П hFig — указатель на графическое окно; П hAxes — указатель на поле графика;
326 Глава 8 П hBtn — указатель на кнопку Решение; П hTxta — указатель на метку а=; П hTxtb — указатель на метку Ь=; П hTxtc — указатель на метку с=; П hTxtxi — указатель на метку xl=; П hTxtx2 — указатель на метку х2=; □ hEda — указатель на поле ввода значения а: П hEdb — указатель на поле ввода значения ь; П hEdc — указатель на поле ввода значения с; П hEdxi — указатель на ноле вывода значения xi; П hEdx2 — указатель на поле вывода значения х2; Вообще говоря, некоторые из этих указателей можно было бы исключить из списка глобальных переменных. Например, метки, представленные объектами гипа static Text, после своего появления на форме изменяться не будут, и их указатели больше никому не потребуются. Создавая форму нашего приложения с помощью функции figure, мы задаем координаты ее нижнего левого угла в пикселах (50, 50), ширину (480) и высоту (300). Эта четверка образует вектор, представляющий значение свойства position. Не забывайте, что начало системы координат расположено в нижнем левом углу экрана, и направление координатных осей совпадает с общепринятым. Указатель на созданную фигуру запоминается в переменной hFig и может быть использован при размещении па форме других графических объектов. Создание поля графика (объект класса Axes) пришлось выполнить в два этапа. Сначала с помощью функции axes было построено поле графика с автоматическим выбором его размеров и положения в графическом окне. А на втором шаге с помощью функции set пришлось изменить значение свойства units. По умолчанию для осей устанавливается режим normalized, при котором нижний левый угол рабочего поля графического окна соответствует точке (0, 0), а правый верхний — точке (1, I). В этих единицах довольно сложно подобрать нужные размеры поля графика (нам это удалось с пятой попытки— [0.1 0.25 о.5Ь 0.68]). Размеры в миллиметрах гораздо удобнее переводить в пикселы, что было и сделано с помощью второй пары аргументов функции set. Указатель поля графика hAxes понадобится в дальнейшем при построении графика- пашей функции. Маркировка осей выполнена по умолчанию, однако после построения конкретного графика эти числовые значения изменятся. Все интерфейсные компоненты создаются с помощью функции uicor-troi, которой передаются указатель на "владельца" (hFig) и тип создаваемого эле-
Проектирование интерфейса 327 мента (значение свойства style). Заметим, что только что созданное графическое окно является текущей фигурой, поэтому в функциях uicontrol первый параметр можно было бы опустить. По умолчанию владельцем создаваемых компонентов является текущая фигура. Для объектов класса static Text (статический, т. е. неизменяемый текст) кроме параметров положения и единиц их измерения задается значение свойства string — текст, который появится в поле метки. Объект класса Push Button тоже снабжается надписью, располагаемой- на кнопке. Для объектов класса Edit Text (редактируемый текст) свойство string по умолчанию представлено пустой строкой, а значение left у свойства HorizontaiAiignment прижимает набираемое значение к левой границе. Все интерфейсные элементы лучше смотрятся, если их фоновый цвет — белый (значение свойства Backgroundcolor). С кнопкой Решение ассоциирован обработчик событий (callback-функция), представленный файлом roots3.ni. Текст этой функции приведен в примере 8.3. Строки функции пронумерованы только с целью комментария. 1. function roots3 2. global hAx.es 3. global hEda hEdb hEdc hEdxl hEdx2 4. axes(hAxes); 5. cla; 6. str=get(hEda,'String'); 7. a=str2num(str); 8. str=get(hEdb,'String'>; 9. b=str2num(str); 10. str-get(hEdc,'String'); 11. c=str2hum.(str) ; 12. p=[a b c]; 13. x=roots(p) 14. xrl=real(x(l)); 15. xr2=real(x(2)); 16. xmin=niin(xrl,xr2) -0.5; 17. xmax=max(xrl,xr2)+0.5; 18. xx=xmin:0.l:xmax; 19. yy=polyval{p,xx); 20. plot(xx,yy) 21. grid on 22. set(hEdxl,'String',num2str(x(1))>; 23. set(hEdx2,'String',num2str(x(2))>;
328 Глава 8 9ftdi*v. "> ^/^ [-П;'ЩЬЩ^ШШ§Ш^*:^ -ЛИЛ] File Edit Text Cell tools Debug Desktop Window Help ■■ - • * j к .x 1 2 3- 4 - 5- 6- T - 8 - 9 - ID 11- 12 13 - 14 15 - 16 •> Figure 1 V a= b= -2 4 function cootsZ i i-.7[QO,3jjt,i-:..« c<bp-.7i«;[ p||e Edi V[ew Insert Too(s [-jg^top W|ndow He[p global hfxg hAxes hB -- --- - ~ - = ~* ~ —-- tllobdl hTxta hTxtb h global hEda hEdb hEd hFig=figure (" Fes it ю ■■'" hAxes=axes; 05 set (hAxes, ' 'Jn.Lt. ', *pi hTxta=uiconteol(hFig 'Position', [340, о hTxtb=uicontcol(hFig - ■ •posiLion',[340, ■. hTxtc=u icont со 1 (hF ig 'Eos L>.ion', [340, hTxtxl=uicontrol(hFi "Position*, [340, НПО 051— '-0j5 / к„,г 0.75 Решение y1= \\.\7A2 *2=. Ic.42583 0,5 1..5 Рис. 8.5. Решение квадратного уравнения После набора значений коэффициентов а, Ь, с в редактируемых полях ввода и щелчка по кнопке Решение возникает событие, для обработки которого автоматически вызывается Callback-функция root3.m. Для страховки четвертой строкой активизируется окно графика, на которое смотрит указатель hAxes. В нашем приложении такое окно единственное, поэтому именно оно и является текущим, следовательно, в обращении к функции axes особой нужды нет. В пятой строке производится очистка текущего поля графика. Затем в строках 6—11 выполняется считывание содержимого тестовых окон и преобразование извлеченных строк в числовой формат. Строки 12—21 повторяют вычислительную схему, апробированную нами в командном окне. Найденные значения корней преобразуются из числового формата в символьный вид и заносятся в соответствующие окна вывода. Результат работы нашего приложения, представленного файлами roots2.ni и roots3.m, приведен на рис. 8.5. 8.1.1. Командная кнопка Командная кнопка типа push Button создается с помощью функции uicontroi, в которой параметру 'style' приписано значение 'pushbutton'. По умолчанию она не снабжается никакой надписью, имеет серый цвет и располагается в левом нижнем углу фигуры (рис. 8.6). Всем ее свойствам, кроме указанной характеристики 'style', присвоены значения по умолчанию, в чем можно убедиться, обратившись к функции get (пример 8.4).
Проектирование интерфейса 329 Рис. 8.6. Создание простейшей командной кнопки | Пример£4. Свойства команднойкнопки -..'i^.r ■ „ ' ■ .** V". V :.'"и » get(hBtn) » BackgroundCblor = [0.831373 0.815686 0.784314] Callback = CData = [] Enable = on Extent = [0 0 4 4] FontAngle = normal FontName = MS Sans Serif FontSize = [8] FontUnits = points FontWeight = normal ForegroundColor = [0 0 0] HorizontalAlignment = center KeyPressFcn = ListboxTop = [0] Max = [1] Min = [0] Position = [20 20 60 20] String = Style = pushbutton SliderStep = [0.01 0.1] TooltipString = Units = pixels Value = [0] BeingDeleted = off
.330 Глава 8 ButtonDownFcn = Children = [] Clipping = on CreateFcn = DeleteFcn = BusyAction = queue HandleVi.sibility = on HitTest = on Interruptible = on Parent = [1] Selected = off SelectionHighlight = on Tag = Type = uicontrol UIContextMenu = [] UserData = [] Visible = on Несмотря на свою безликость (отсутствие надписи и собственного имени) созданная кнопка умеет утапливаться при щелчке левой кнопкой мыши в тот момент, когда ее курсор находится над поверхностью кнопки. Именно эта акция вызывает появление события callback для кнопки, однако в нашем приложении не была предусмотрена ответная реакция (указатель Callback "смотрит" в никуда). Попробуем модифицировать процедуру создания кнопки, задав дополнительно значения некоторых свойств (рис. 8.7). function pushbtn hfig=figuceС Position', [200,200,300,100]) ; tiBtn=uicontrol('Sty.lir:', 'pushbutton1, ... 1 st ring','кнопка I'); ♦> Figure 1 НПП File Edit View Insert fools Desktop Window Help » Кнопка 1 Рис. 8.7. Кнопка с надписью (Strings ' Кнопка 1')
Проектирование интерфейса 331 Теперь при щелчке на кнопке вокруг ее надписи появляется пунктирный прямоугольник, свидетельствующий о том, что кнопка "находится в фокусе". Щелчок за пределами поверхности кнопки выведет ее из фокуса, и пунктирная рамка пропадет. Добавим еще одну кнопку, сместив ее на 80 пикселов вправо (рис. 8.8). function pushbtn hfig=figureГ Position",[200,200,300,100]); hBtnl=uicontrol('style','pushbutton',... 'St ring', *Кнопка 1') ; hBtn2=uicontrol('Style','pushbutton', ... 'St ring','Кнопка 2 ', ... 'Position',[100,20,60,20]); -> Figure 2 НПО File Edit View Insert Tools Desktop Window. Help ■». ■>-., v*~ "' '' *'*? l^ifeK^^Jife^ ■■."- »-~№Й7 "йЗрчй^' Кнопка 21 " : -■". Гт.Д: Рис. 8.8. Две кнопки на форме Позицию второй кнопки мы сформировали по позиции первой, которая была привязана левым нижним углом к точке с координатами (20, 20), имела ширину 60 и высоту 20 пикселов. Теперь щелчки на любой из кнопок создают пунктирную рамку вокруг надписи выбранного элемента. Передача фокуса от одной кнопки к другой возможна и путем нажатия клавиши <ТаЬ> (или комбинации клавиш <Shift>+<Tab>). Однако главным назначением командной кнопки является вызов процедуры, реагирующей на соответствующее событие Callback. Поэтому нашим следующим шагом станет создание m-файла, который будет вызываться системой автоматически в случае щелчка по той или иной кнопке. Назовем эту функцию pushbtni и возложим на нее обязанности реагировать на щелчок по первой или второй кнопке. Например, пусть в случае щелчка по кнопке I на ней появляется надпись Нажата 1, а на кнопке 2 восстанавливается ее начальный заголовок. А в случае щелчка по кнопке 2 на ней появляется надпись Нажата 2 и восстанавливается начальный заголовок на кнопке 1. Для упрощения процедуры анализа, по какой из кнопок произошел щелчок, объявим указатели hBtni и hB.tn2 глобальными и при попадании в обработчик события callback проверим указатель объекта — инициатора события. Значение последнего опрашивается с помощью функции gcbo (пример 8.$).
332 Глава 8 function pushbtn % Головная программа, создающая форму с двумя кнопками global hBtnl hBtn2 hf ig=f igure (' Position', [200,200,.300,100]); hBtnl=uicontrol('Style','pushbutton', ... 'String','Кнопка 1',... 'Position',[10,20,70,25],... 'Callback','pushbtnl'); hBtn2=uicontrol('Style','pushbutton',... 'String','Кнопка 2',... ' Position', [100,20, 70, 25.] 'Callback','pushbtnl'); end function pushbtnl % Обработчик события Callback для обеих кнопок global hBtnl hBtn2 set(hBtnl,'String','Кнопка 1') set(hBtn2,'String','Кнопка 2') if gcbo=hBtnl set(hBtnl,'String','Нажата 1") end if gcbo=hBtn2 set(hBtn2,'String','Нажата 2') end После запуска головной программы pushbtn появляется форма с двумя кнопками, щелчки по которым вызывают описанную смену заголовков (рис. 8.9). ( Замечание J Если обработчик события callback вынесен в отдельный m-файл, то приведенный выше пример работает правильно. У этого решения есть свои плюсы и минусы. К автономному обработчику событий могут обращаться разные функции, но выделение его в отдельный файл ведет к увеличению общего числа файлов в составе приложения. Однако обработчик pushbtnl может быть включен в число подфункций файла pushbtn.т. Для этого функция pushbtn вместо необязательного оператора end должна заканчиваться опера-
Проектирование интерфейса 333 тором waitfor (hfig). функция waitfor (hf ig) ожидает события "Уничтожение объекта" с указателем hf ig. Поэтому выход из файла pushbtn задерживается, и функция pushbtnl имеет доступ к рабочему пространству головной функции, т. е. к глобальным переменным hBtnl и hatn2. Без такой задержки callback- события происходят после выхода из файла pushbtn и указанные переменные в глобальном рабочем пространстве уже не видны. •> Figure 1 File,' Edit View " H' - Insert Кнопка 1 | |Нажатз2| . i«»A«-i . . - *-■ Tools 7.3£ - 4-- Desktop :»i ;>'-; Window.. ипп Help Рис. 8.9. Кнопки, реагирующие на события Кнопка, как и любой другой интерфейсный компонент, может быть снабжена всплывающей подсказкой, текст которой задается в свойстве TooltipString (рис. 8.10). function pushbtn global hBtnl hBtn2 hfig=figuce(,Posit.Lori,# [200,200,300,120]) ; hBtnl=uicontcol('Style','pushbutton',... 'String *,'Кнопка 1',.. . •Position',[10,20,70,25], ... •Callback*, 'pashbtnl') ; set(hBtnl,'ToolcipStcing','Командная кнопка'); -/Figure 1 ЯОЕЗ File Edit View Insert Tools Desktop Window Help ■» j.:'- .--¾¾¾^¾. л-- •%•:- .-- 4ff^r "' r-b Кнопка 1 I Кнопка 2. | ■■'-'- (Командная кнопка| ■ ---1 Рис. 8.10. Всплывающая подсказка у командной кнопки В отличие от большинства визуальных сред, где цвет командных кнопок остается неизменным, MATLAB позволяет окрасить поверхность кнопки в любой цвет и использовать любой цветовой оттенок для символов надписи. Для этого достаточно задать нужные значения свойств BackgroimdCoior и
334 Глава 8 Foregroundcoior (пример 8.6). Ими могут быть символьные константы, определяющие наиболее используемые цвета, или трехкомпонентные векторы, устанавливающие интенсивности RGB-составляющих. ™гч; ■?;."" w v.".-" ■; v^;;----™^-^:---.--.:--.-.- ■ •» -,- ;-.- :-.ут - \. Призер,6,6. Разноцветные ^оманднмв кнопки .¾¾.. . я . и у, *-,". /-LJ-. f ,; hBtnl=uicontrol('Style','pushbutton',... 'String','Кнопка 1',... •Callback",'pushbtnl'); setfhBtnl,'BackgreundColor',[0 1 0],... 'ForegroundColor', 'Red') ; В приведенном выше примере будет создана зеленая кнопка с красной надписью. Аналогичную раскраску допускают и некоторые другие интерфейсные компоненты. Событие callback не является единственным событием, которое может быть связано с командной кнопкой. Второе по значимости событие, ассоциируемое со свойством ButtonDownFcn, возникает в одной из следующих ситуаций: П происходит щелчок левой или правой кнопкой мыши в тот момент, когда острие курсора находится снаружи контура в пределах 5-пиксельной зоны кнопки; □ происходит щелчок правой кнопкой в тот момент, когда острие курсора мыши находится внутри контура кнопки. Событие ButtonDownFcn не вызывает каких-либо изменений во внешнем виде кнопки, она не утапливается, как это происходит в случае основного события callback. Более того, обработчик события Callback можно заблокировать, установив свойство Enable в состояние off (доступ запрещен) или inactive (кнопка не активна). Обработчик события ButtonDownFcn в любом из этих случаев все равно будет автоматически вызван, и этим можно воспользоваться, например, для изменения размеров или положения кнопки. В большинстве визуальных сред подобным образом осуществляют буксировку компонентов (технология drag & drop). Существуют еще два события, характерные для всех интерфейсных элементов, возникающие в момент создания и уничтожения объекта. На первое из них реагирует функция, на которую "смотрит" указатель createFcn. Это событие возникает непосредственно вслед за созданием компонента, так что его обработчик может воспользоваться свойствами появившегося объекта Функция — обработчик события DeieteFcn получает управление непосредственно перед удалением объекта и еще может использовать в своей работе значения свойств уничтожаемого компонента.
Проектирование интерфейса 335 8.1.2. Кнопка, фиксирующаяся в утопленном состоянии Кнопка типа Toggle Button отличается от командной кнопки тем, что фиксируется в утопленном состоянии после первого щелчка и возвращается в начальное состояние после следующего щелчка. Такие кнопки, как правило, используются на панелях инструментов или в палитрах компонентов. Вместо надписи на них обычно размещают небольшие изображения, которые могут изменяться в зависимости от состояния кнопки. Продемонстрируем эту возможность на примере кнопки с изображением увеличительного стекла (стандартная операция Zoom (Масштаб) в большинстве графических систем). Рисунок для этой кнопки был сделан с помощью редактора Paint по следующей схеме. После запуска редактора была нажата клавиша <Print Screen> для запоминания среды редактора в буфере обмена. Затем содержимое буфера обмена было извлечено по команде Правка | Вставить (Edit | Paste), изображение соответствующей кнопки было вырезано и сохранено в формате 24-разрядного рисунка с расширением bmp (файл zoom.bmp). С помощью функции tbutton формируется графическое окно с двумя фиксирующимися кнопками. Содержимое файла с изображением лупы считы- вается в массив, а с помощью функции imread и загружается в свойство cData обеих кнопок (пример 8.7). На рис. 8.11 показана форма приложения, на которой одна из кнопок зафиксирована в утопленном состоянии. | Призер 817. функция tbatton. ^¾¾¾¾¾^ '»'J?1 "J ' "" '.' ' ■•• function tbutton hFig=figure<'Position',[50,50,300,100]); hTBtnl=uicontrol('Style','togglebutton',... 'Position',[50,50,30,30]); a=imread('zoom.bmp','bmp'); set(hTBtnl,'CData', a); hTBtn2=uicontrol('Style','togglebutton*,... 'Position',[62,50,30,30]); set (hTBtr_2, ' CData', a) ; Для того чтобы в обработчиках событий разобраться, в каком состоянии находится кнопка, необходимо проанализировать значение свойства Value. Если оно совпадает со значением свойства мах, то кнопка находится в утопленном состоянии. Равенство vaiue=Min означает, что кнопка отжата.
336 Глава 8 •> Figure 1 ВПЕЗ Flle_ Edit .View Insert; Tools. Desktop Window. Help ■* --"4tf Рис. 8.11. Фиксирующиеся кнопки 8.1.3. Рамки, индикаторы альтернативных и неальтернативных комбинаций Новые интерфейсные компоненты типа Panel и Button Group используются в качестве рамок-контейнёров, во внутренней области которых группируются однотипные индикаторы альтернативных (Radiobutton) или безальтернативных (checkbox) компонентов. Конечно, в панели можно размещать компоненты и других типов. Удобство таких контейнеров заключается в том, что они перемещаются по графическому окну вместе со своей начинкой. Во-вторых, рамки могут быть снабжены пояснительной надписью, как это делается в других визуальных средах. К сожалению, непосредственная манипуляция с новыми интерфейсными компонентами достаточно сложна. Поэтому знакомство с ними мы отложим до разд. 8.3. •> Figure 1 ВПЕЗ File Edit View Insert Tools Desktop Window .Help, . -» 1 0.8 0.6 0.4. 0.2 0 J. - -*. Г бВД. •: r cosfr) 4Г D 0.2 0.4 0.6 0.8 1 Рис. 8.12. Приложение с лереключатеугсми
Проектирование интерсрейса 337 А пока продемонстрируем использование переключателей на примере выбора функции, график которой должен воспроизводиться в поле hAxes. Далеко не с первого раза нам удалось подобрать подходящие размеры и расположение компонентов, представленных на рис. 8.12. Если размеры и положение рамки с кнопками были установлены сравнительно быстро, то поле графика упорно не хотело рисоваться до тех пор, пока не было задано значение свойства units. По умолчанию единицы измерения соответствуют режиму Units=r.ormalized, но позицию компонентов привычнее задавать в пикселах. Оказалось, что важны не только единицы измерения, но и тот факт, что они должны быть установлены до задания положения и габаритов поля графика (т. е. на порядок задания свойств в функции set следует обращать внимание). Соответствующая заготовка файла buttongroupl.m без ссылок на обработчики событий Callback содержит операторы, представленные в примере 8.8. &&А .!.:;.■ .гл. ". ".si&i^.iA..M£-&..it«i3l .-.ш'ЗиЛ'.*..-.-. гя.гйй..." Ш~я . Г\, .... smL* .«л?;-..*7..... !. Ллк:.-.....\Ш.'! function buttongroupl global hAxes global hRbl hRb2 hBb3 hFig=figure(' Position1, [50,50,500,30.0]) ; hAxes=axes; set(hAxes,'Units','pixels','Position',[50,50,350,230]); hRbl=uicontrol('Style','radiobutton',... 'String','sin(x) ', . . . 'Position',[420,250,60,20]); hRb2=uicontrol('Style', *radiobutton',... 'String','cos(x)',... 'Position',[420,220,60,201); hRb3=uicontrol('Style','radiobutton',... 'String','exp(x)',... 'Position',[420,190,60,20]); Несколько разочаровало то, что после запуска программы buttongroupl щелчки по любой радиокнопке (переключателю) приводили к ее выделению независимо от состояния других кнопок. Поэтому восстановление справедливости пришлось перенести на обработчики события callback, которые удалось объединить, в функции radioI.m (пример 8.9).
338 Глава 8 w'm?""® %■ активизация объекта hAxes % очистка поля графика % если был сделан щелчок по первой кнопке % сброс альтернативных кнопок % сброс альтернативных кнопок % построение синусоиды function radiol % функция для обработки событий Callback global hAxes global hRbl hRb'2 hRb3 axes(hAxes) cla x=0:0.1:6.28; if gcbo==hRbl set(hRb2,•Value',0) set(hRb3,'Value',0) y=sin(x); plot(x,y); end if gcbo=hRb2 % если бьш сделан щелчок по второй кнопке set(hRbl,'Value',0) % сброс альтернативных кнопок set(hRb3,"Value',0) % сброс альтернативных кнопок y=cos(к); plot(х,у); % построение косинусоиды end if gcbo==hRb3 % если был сделан щелчок по третьей кнопке set(hRbl,'Value',0) % сброс альтернативных кнопок set(hRb2,'Value',0) % сброс альтернативных кнопок у=ехр(х); semilogy(х,у); %: построение экспоненты end grid oil % нанесение сетки Одно из альтернативных состояний приложения с выделенным графиком функции у = ех приведено на рис. 8.13. Событие callback для переключателя возникает не только в момент щелчка левой кнопкой мыши, когда острие ее курсора находится внутри окружности, обозначающей кнопку. К внутренней области кнопки относится и прямоугольник с пояснительной надписью, и щелчок по надписи также приводит к выделению кнопки. Для выделенной кнопки автоматически устанавливается значение свойства value, по умолчанию совпадающее со значением свойства мах и равное д.. Отмена выделения других альтернативных кнопок
Проектирование интерфейса 339 возлагается на программиста и сводится к установке нулевого значения их свойств Value. ■> Figure 1 НПО File Edit View insert Tools Desktop Window Help ■» юэ 101 101 . 10° ( '; ' " _■ """ "~ ё^шйёшё^ш i \--^.i-..- =:::::rt:::::;::::::;-:::= --^--- f ---4-- • ; Г cosM с exp[x) : * Э - 2 7-,..4 A --. 6. 8 .. ' ■ .-: - . .1 Рис. 8.13. График у = e* в полулогарифмическом масштабе Кнопки типа checkbox (флажки), используемые для индикации неальтернативных комбинаций, отличаются от переключателей только формой — квадратиком, в котором при выделении кнопки пояштяется галочка. Генерация события Callback и автоматическое выделение кнопки происходят при щелчке на квадратике или сопровождающей его надписи. Если кнопка типа Checkbox выделена, то значение ее свойства value совпадает со значением свойства мах, по умолчанию равного х. Повторный щелчок по кнопке checkbox автоматически изменяет ее состояние на противоположное. Модифицируем предыдущий пример, заменив в нем переключатели на флажки checkbox. В зависимости от комбинации отмеченных флажков в поле графика должна появиться координатная сетка, синусоида, косинусоида или оба графика вместе. Головная программа buttongroup2.ni мало чем отличается от предыдущей, разве что на одну кнопку стадо меньше (пример 8.10). |м.ч;,ь"чд?/л*ч.; •' ||Прим;ер8.10.ФуНкц^ШЪ%>пдгоир2 i£. ; .- аШЕ^ЕГЗ function buttongroup2 global hAxes global hCbl hCb2 hFig=f igure [' Position', [50,50, 500,300]) ,- hAxes=axes('Units','pixels','Position', [50,50,350,230]);
340 Глава 8 hCbl=uicontrol('Style','checkbox',... 'String','sin(x)', ... •Position', [-920,250,60,20], . . . • Callback','checkl'>; hCb2=uicontrol('Style','checkbox', . . . 'String','cos(x)',... 'Position',[420,220,60,20],... 'Callback','checkl'); В обработчике события Callback пришлось позаботиться только о том, чтобы после воспроизведения какого-либо графика была возможность построить график другой функции. В этом нам помогла процедура hold on, предотвращающая создание нового фафического окна при выполнении в очередной раз функции plot (пример 8.11). :-;£?«Д|.,.-у.л.-.. .&&<№,« .-. .-; . . S .ii ..ййМаяшяяЯт ш&№&-..,!..: '$ .; ' ... Я51..:?л;х]н..-л* uisa£S&: function checkl global hAxes global hCbl hCb2 axes(hAxes) cla get(hCbl) get(hCb2) x=0:0.1:6.28; % если первая кнопка выделена if (get (пСЫ, 'Value' )==1) y=sin(x); plot(x,у); hold on end % если вторая кнопка выделена if (get (hCb2,'Value')=1) У=соб(x) ; plot(x,y); hold on end grid on Один из фрагментов работы описанного приложения приведен на рис. 8.14.
Проектирование интерфейса 341 •> Figure 1 НПЕЗ gie_gdlt View insert_TOob Desktop. Window Help .^. _^ * ' 1 0.5 f). 0 -05 0 2 4 6 8 Рис. 8.14. Два графика — оба флажка отмечены 8.1.4. Ввод, редактирование и отображение текстов Поле отображения текстовой информации— объект типа static Text — является полным аналогом визуальных компонентов типа Label. Он предназначен для вывода символьной строки (или нескольких строк) в выделенном прямоугольнике. Отображаемый текст — значение свойства string — не может быть изменен пользователем. С помощью функции static_text.m (пример 8.12) формируется окно (рис. 8.15), содержащее 4 ПОЛЯ С разными значениями свойства HorizontalAlignment (горизонтальный прижим). »> Figure 1 ипи File Edit View Insert Tools Desktop Window Help * Метка A Метка 3 Метка 2 Метка 1 " J' Рис. 8.15. Метки с различным расположением текста / \ ■\ \ \ -V i Л А уу ; :.Psin(x) 17 cos(x) ч&Ш
342 Глава 8 По умолчанию для объекта установлен центральный прижим (HorizontaiAiignment=center), что хорошо просматривается на тексте Метка 4. Белый фон окаймляющего прямоугольника позволяет более четко рассмотреть положение выводимого текста. ?»"•-' ■-.-„w^jf.-ewivvr ^л"^гщг^тщ^«ж^-теч^«й^^^Ш5а^^Щ"'"~"'""г"'"'?'"тг: "*: :&£:£:!::^..К^^ .-.. .:1 function static_text hFig=figure('Position',[50,50, 300, 200J) ; hStl=uicontrol('Style','text','Position',[30,30,150,20],... 'HorizontalAlignment', 'left', ... 'BackgroundColor',[1 1 1],•String','Метка 1') ; hSt2=uicontrol('Style','text','Position',[30,60,150,20],... 'HorizontalAlignment','center',... 'BackgroundColor',[1 1 1],'String','Метка 2'); hSt3=uicontrol('Style','text','Position',[30,90,150,20],... 'HorizontalAlignment','right', ... 'BackgroundColor',[1 1 1],'String','Метка 3'); hSt4=uicontrol('Style','text','Position',[30,120,150,20], ... 'BackgroundColor',[1 1 1],'String','Метка 4'); Варианты создания многоэтажной надписи (рис. 8.16) демонстрирует программа static_text2 (пример 8.13). ! Пример В\{^.Фуьщ^я-в^^щ2^Ш^\.§:н' -.4^ -ЙЙ^'Ч---- ч" ■ I function static_text2 hFig=figure('Position',[50,50,300,200]); hStl=uicontrol('Style",'text','Position', [30,30,60,55], . . . 'HorizontalAlignment', 'left', ... 'BackgroundColor', [1 1 1],... ■String',{'Строка 1','Строка 2','Строка 3'}); hSt2=uicontrol('Style','text','Position',[30,120,60,55],... 'HorizontalAlignment','left',... 'BackgroundColor',[1 1 1],... 'String',['String 1';'String 2';'String 3']); Интерфейсный элемент типа Edit Text (редактируемый текст) может использоваться как для вывода символьной информации, так и для ввода
Проектирование интерфейса 343 строк во время работы программы. Текст, набираемый в поле ввода, можно корректировать, производить вставки и удаления, использовать фрагменты из буфера обмена. Процедура ввода, завершаемая нажатием клавиши <Enter>, генерирует событие callback. Второй способ генерации этого события происходит в момент потери фокуса окном ввода. Для этого нужно после набора данных перевести курсор мыши за пределы окна ввода и произвести там щелчок левой или правой кнопкой. -> Figure 1 НПО File gdlt^lew ]nsert_Tools Desktop WlndouHelp ■» Slnng 1 Slnng2 Slnng 3 Строка 1 Строка 2 Строка 3 Рис. 8.16. Многострочные метки В программе edittextl.m (пример 8.14) демонстрируется стандартная техника ввода данных, которые после возникновения события callback переносятся в окно статического текста. Две другие метки используются для идентификации полей ввода и вывода (рис. 8.17). \ Прим^й.1-С<Ьуйкцияedxtjbe«ti vf^-^Й-^-^'-* - !'""'' ^~*\^-^-^jj0£M function edit_textl global hEd hSt hFig=figure['Position', [50,50,400,150]); hStl=uicontrol('Style','text','Position',[30,30,150,20],... 'String','Окно ввода'); hSt2=uicontrol('Style','text','Position', [200,30,150,20], ... 'String','Окно вывода'); hEd=uicontrolС Style','edit','Position', [30,60,150,20],... 'BackgroundColor',[1 1 1],'Callback','textl'); hSt-uicontroi('Style', 'text','Position',[200,60,150,20],... 'BackgroundColor', [1 1 1]'); 12 3ак. 899
344 Глава В -> Figure 1 НПО File Edit View Insert Tools/Desktop Window Help * '■'^"' '.'"Г»*' '" =¾1^1 "'■ ' *""'''л:1 v- ■' ■I " & - ^d,~,s Окно ввода Окно вывода " , Г' Рис. 8.17. Форма приложения для ввода строки Обработчик события callback переписывает содержимое поля ввода в окно вывода (пример 8.15). function textl global hEd hSt s=get(hEd,'String'); set(hSt,'String',s) Результат работы этой простенькой функции представлен на рис. 8.18. ~> Figure 1 НПО File Edit View Insert Tools Desktop Window Help « й^'-'-^1^г; | Helic. world! Окно ввода Hello, worldl Окно выводе Рис. 8.18. Пример ввода символьной строки Вводимый текст может быть прижат к левому или правому краю окна ввода, если задать соответствующее значение свойства HorizontalAlignment. Если вводимый текст представляет собой числовое значение, которое должно быть использовано в работе программы, то содержимое свойства string переводится в числовой формат с помощью функции 5tr2num (в примере с решением квадратного уравнения именно так и поступали при вводе коэффициентов а, ь, с).
Проектирование интерфейса 345 8.1.5. Списки строк Интерфейсный компонент типа Listbox представляет собой окно, в котором может находиться список строк. Если длина списка превышает высоту окна, то для перемещения по списку может использоваться вертикальная полоса прокрутки. Список позволяет пользователю выбрать одну или несколько строк и в зависимости от выбора произвести то или иное действие. Список, предоставляющий возможность выбрать единственную строку, характеризуется тем, что разность между значениями его свойств мах и Min равна 1. По умолчанию это условие выполнено, т. к. мах=1, a Min=o. Выбор строки осуществляется щелчком левой кнопки мыши в тот момент, когда острие курсора указывает на выбираемую строку. Одновременно с подсветкой строки ее номер заносится в свойство Value и генерируется событие callback. Строки в. списке нумеруются от 1. Если разность Max-Min превышает 1, то список допускает множественный выбор. Сделать его можно несколькими способами. Для выбора разрозненных строк нужно зажать клавишу <Ctrl> и щелкать мышью по выделяемым строкам. При этом каждая выделяемая строка подсвечивается, а ее номер запоминается в векторе value. Для выбора группы подряд идущих строк можно нажать и удерживать клавишу <Shift>, а затем щелкнуть по первой и последней строке группы. Все промежуточные строки тоже будут выделены и все их номера запомнятся в векторе Value. При групповом выделении событие callback возникает в момент отпускания кнопки мыши (таким образом, это случится сразу же после выделения первой строки). Поэтому обработку выделенных строк следует увязать с каким-нибудь другим интерфейсным элементом, например, кнопкой с надписью Выбор сделан. И уже в ее обработчике события Callback разбираться с компонентами вектора value, принадлежащими списку. Продемонстрируем работу с небольшим списком на примере построения одной из функций — sin(x), cos(x) или ехр(х). Процедура создания и заполнения списка включена в состав функции listl.m (пример 8.16). [^йм!^^ ■ *** ''". - - ^Ш&Ж?&&Шь!*ё';| function listl global hAxes hLB hFig=figure('Position', [50,50,500,300]); hAxes=axes['Units','pixels','Position',[50,50,300,230]) ; hLB=uicontrol('Style','listbox',... ■String',{'sin(x)','cqs(x)','exp(x)'},...
346 Глава 8 •Position",[370,150,100,100],... •BackgroundColor',[1 1 1],... •Callback',4ist2'); Обратите внимание на технику заполнения списка. Значением свойства string здесь является массив ячеек, т. к. длины строк могут быть разными. Этот массив можно было бы сформировать отдельно, сохранив, например, под именем stri: strl = {'sin(x)','cos(х)','ехр(х)'); И тогда задание свойства string могло иметь следующий вид: 'String',strl,... Так как серый фон списка смотрится хуже, его заменили белым фоном (см. значение свойства BackgroundColor). Обработчик события Callback оформлен в виде функции Hst2.m (пример 8.17). function list2 global hAxes hLB x=0:0.1:6.2B; axes(hAxes) k=get(hLB,'Value'); switch (k) case 1 y=sin(x); case ? y=cos(x) ; case 3 y=exp(x) ; end с la plot(x,y Результат работы описанного приложения приведен на рис 8.19.
Проектирование интерфейса 347 •> Figure 1 НПО File Edit View Insert Tools Desktep Window Help . ■» 500 400 300 200 100 / / / / / У \ i'.- ) 2 4 ,. 6 .8 ' ^ ■*& «W ij." i ife. r- Рис. 8.19. Выбор графика функции с помощью списка 8.1.6. Полоса прокрутки Интерфейсный компонент типа Slider представляет собой обычную полосу прокрутки, которую можно использовать либо в качестве средства ввода числового значения из диапазона [Min, м.ах], либо в качестве индикатора объема выполненной работы. В зависимости от соотношения длины w и высоты h, заданных в качестве значения свойства Position=[x у w h], полоса прокрутки принимает горизонтальное (w > h) или вертикальное (w < h) положение. Точка с координатами (х, у) соответствует позиции левого нижнего угла полосы. Смещеггие ползунка (в горизонтальном положении — относительно левой границы, а в вертикальном — относительно нижней границы) линейно изменяет значение свойства Value в диапазоне от минимума (значение свойства Min) до максимума (значение свойства мах). По умолчанию Min=o, а мах=1. Пользователь может перемещать ползунок тремя способами: D захватив ползунок мышью с нажатой левой кнопкой и перемещая его в том или ином направлении до момента отпускания кнопки; О щелкая по одной из граничных стрелок полосы прокрутки (малый шаг); □ шелкая по области полосы между ползунком и стрелкой (большой шаг). Каждое из этих действий вызывает событие callback. В двух последних случаях величина смешения ползунка определяется компонентами свойства siiderstep=[hl h2]. Первая составляющая этого вектора (по умолчанию hi=0.oi) определяет долю малого шага, а вторая составляющая (по
348 Глава 8 умолчанию h2=o.l) — долю большого шага относительно длины интервала (Max-Min). Для изменения положения ползунка программным путем достаточно изменить значение свойства Value, например, с помощью функции set. Продемонстрируем поведение полосы прокрутки в следующем приложении. Поместим на форму приложения горизонтальную линейку, положение ползунка которой будет отслеживать упомянутые выше манипуляции. Текущее значение свойства Value отображается в поле вывода обработчиком события Callback (функция sid). Ползунок вертикальной полосы отображает значение числа, набираемого в поле ввода. Текст программы и обработчики событий Callback приведены в примере 8.18. ;Пример 8.18. Функция sli^rl ^;j^bi^^il^^H ^., . ^5,.. ^¾¾¾1 * И<.-» function sliderl global hStl hEd2 hSldl hSld2 hFig=figure('Position',[50,50,400,300]); ftStl=uicontrol('Style','text','Position',[135,25,60,20],... •Backgroundcolor',[1 1 1],'String', ' 0'); hSldl=uicontrol('Style','slider','Position',[50,50,200,20],... 'Callback','sld'); uicontrolfStyle','text','Position',[50,25,80,20],... 'String','Окно вывода'); hEd2 =uicontrol('Style','edit','Position', [260,255,40,20], ... 'Backgroundcolor',[1 1 1],'String*,'0',... •Callback','fed'); uicontrol('Style','text','Position',[170,255,80,20], ... 'String','Окно ввода'); hSld2=uicontrol('Style','slider','Position',[270,50,2Q,200]); % Обработчик события Callback горизонтальной линейки function sld global hStl hSldl set(hStl,'String',num2str{get(hSldl, 'Value'))); % Обработчик события Callback для окна ввода function fed global hEd2 hSld2 set[hSld2,'Value',str2num(get(hEd2,'String')));
Проектирование интерфейса 349 Общий вид приложения приведен на рис. 8.20. •> Figure 1 ЯПЕЗ File Kit view insert Tools Desktop Window Help * . ■,'.-■'.„."" '-'■' v *• - -v*'■•;.■* 1¾¾^.. i; ■ ■■ ■■"-" ■ '■ '^■.■г*^/ Г'' _j—_^, —j— ..-. -J .. Окисей «.V^ :-.- «№*-' ■Ш t *:li*m Рис. 8.20. Приложение с линейками прокрутки Так как обработчики событий представлены простейшими функциями, то использование анонимных функций позволяет написать более компактную программу, состоящую из единственного файла (пример 8.19). function slider2 global hStl hEd2 hsldl hsid2 hFig=figure (' Position', [50, 50, 400, 300]) ,- hStl=uicontrol('Style*,'text*,'Position*,[135,25,60,20],... 'Backgroundcolbr', [1 1 1],'String','0'),■ hSldl=uicontrol(*Style','slider','Position',[50,50,200,20],... 'Callback', 'sld'); uicontroK'Style','text','Position',[50,25,80,20],... 'String','Окно вывода'),- hSd2 = uicontrol('Style','edit','Position',[260,255,40,20], .. . 'Backgroundcolor',[1 1 1],'String','0',... 'Callback', 'fed'); ui'control('Style','text*,'Position',[170,255,80,20], ... 'String','Окно ввода'); hSld2 = uicontrol('Style','slider','Position',[270,50,20,200]); fed = @() set(hSld2,'Value',str2num{get(hEd2,'String'))),- sld = GO set(hStl,'String',num2str(get(hSldl,'Value')));
350 Глава 8 8.2. Создание всплывающего меню Всплывающее (или контекстное) меню может быть приписано любому интерфейсному компоненту или графическому объекту. Оно появляется в момент нажатия правой кнопки мыши, если ее указатель находится на территории компонента или в непосредственной близости от объекта. Создается всплывающее меню по следующей схеме: 1. С помощью функции uiconextmenu создается указатель на всплывающее меню: hMenu = uicontextmenu; 2. С помощью функций uimenu формируются команды меню, с каждой из которых связывается функция обработки события Callback: iteml=uimenu(hMenu,'Label','имя_команды1', * Callback *,cbf1); item2=uimenu(hMenu,'Label','имя_команды2','Callback',cbf2); item3=uimenu(hMenu,'Label','имя_командыЗ','Callback',cbf3); 3. Указатель на всплывающее меню присваивается свойству uicontextmenu того объекта, с которым мы связываем созданное меню: set(hObj,'Uicontextmenu',hMenu); Продемонстрируем эту схему на примере всплывающего меню, которое изменяет стиль линии нарисованного графика. Для этой цели достаточно изменить значение свойства линии Linestyle (пример 8.20). ...„.„....,,v„.^...,,..^^^^ Шример 8.20. Всплывающее меню с Са&Ш&)&ф^ function popupjmenu global hLine hMenu=uicontextmenu; % создание указателя на меню х=0:0.1:6.28; % задание аргумента y=sin(x); % формирование значений функции hLine=pldt(х,у,'Uicontextmenu',hMenu); % построение графика % создание команд всплывающего меню iteml=uimenu(hMenu,'Label','штриховая','Callback','cbl'); itern2=uimenu(hMenu,'Label','пунктирная', * Callback','cb2'); item3=uimenu(hMenu,'Label','сплошная•,'Callback','cb3'); end f
Проектирование интерфейса 351 function сЫ "*• global hLine set(hLine,'LineStyle','—'); end % штриховая линия function сЬ2 global hLine set (h.Line, 'LineStyle' ,':'); end % пунктирная линия function сЬЗ global hLine set(hLine,'LineStyle','-'); end % сплошная линия Результат работы этого мини-приложения представлен на рис. 8.21. Не забудьте только поместить функции обработки команд меню в отдельные т- файлы. •> Figure 1 .File Edit View Insert Tools DcSsyal fe|Sl€lf7® mi- A.- Й . \ -0.5 Desktop Window M.I D Щ а lu HDD i Help. ... ■•' ]•■■;: »- ■ ■ ■ -^t: ^, ■ / - ■ * пунктирная сплошая \ \ / / / / ) 1-2 3 4 5 ' sfe . ■.-'- --- г "'■ Рис. 8.21. Иллюстрация работы всплывающего меню Обработчики событий могут быть оформлены и как строки в теле головной функции. Обратите внимание на то, что в примере 8.21 в состав строк
352 Глава 8 включены описания глобальной переменной hLine и все кавычки в командах заменены двойными кавычками. I Прйм^&ЙГЙспрльзрванйвстрок при- обработ й.ком^Д'й^ню;^**'^^^'^^^ function popup_menu2 global hLine hMenu=uicontextmenu; % создание указателя на меню х=0:0.1:6.28; % задание аргумента y=sin(х); %■ формирование значений функции hLine=plot(х,у,'UlContextmenu',hMenu);к построение графика % описание строк — функций обработки событий сЫД.= ' global hLine, set (hLine, ''LineStyle'', '' —'')'; % штриховая линия cb21='global hLine, sot(hLine,''LineStyle'','':'')'; % пунктирная линия cb31='global hLine, set(hLine,''LineStyle'',''-'')'; % сплошная линия % создание команд всплывающего меню iteml=uimenu(hMenu,'Label','штриховая','Callback',cbll); item2=uimenu (hMenu, ' Label', ' пунктирная', ' Callback', cb21) ,- itera3=uimenu(hMenu,'Label','сплошная','Callback',cb31); 8.3. Проектирование интерфейса в среде GUIDE Динамический способ проектирования интерфейса в системе MATLAB обладает рядом недостатков по сравнению с возможностями, которые предоставляют наиболее распространенные среды визуального программирования. Во-первых, программа приложения, формируемая пользователем, разбухает за счет операторов, создающих интерфейсные элементы. В визуальных средах интерфейсные элементы включаются в окна приложения путем их перетаскивания из палитры компонентов и настройки нужных свойств с помощью достаточно удобных редакторов типа Object Inspector (Инспектор объектов). И ни одной строчки кода для этой цели писать пользователю не приходится (все заботы по обустройству интерфейса приложения визуальная среда берет на себя). Кроме того, внешний вид большинства интерфейсных компонентов в визуальной среде можно наблюдать и корректировать до запуска приложения. Во-вторых, в визуальной среде очень просто управлять положением интерфейсных элементов на форме и их размерами.
Проектирование интерфейса 353 Наконец, в визуальных средах унифицированы форматы вызова обработчиков различных событий и перечни передаваемых им параметров. Оболочка для каждого обработчика формируется визуальной средой автоматически. Пользователю остается только заполнить тело предоставленной процедуры. Все это послужило поводом к созданию в рамках системы MATLAB сервисных средств, упрощающих проектирование интерфейса приложения. Перечень этих средств приведен в табл. 8.3. Таблица 8.3 Наименование Назначение GUIDE (GUI Builder) Конструктор графического интерфейса Property Inspector Инспектор свойств Object Browser Просмотр объектов M-file Editor Редактор m-файлов Component Callbacks Создание функций обработки событий для компонентов Figure Callbacks Создание функций обработки событий для окна Align Objects Выравнивание объектов Grid and Rulers Управление сеткой и линейками Menu Editor Создание и редактирование меню Tab Order Editor Изменение порядка активизации компонентов при нажатии клавиши <ТаЬ> 8.3.1. Вызов редактора GUIDE Редактор GUIDE (Конструктор фафического интерфейса) является главным инструментом в конструировании графического интерфейса приложения. Его первоначальная настройка производится после выполнения цепочки команд File | Preference | GUI (Файл | Предпочтения | Интерфейс). При этом появляется окно, представленное на рис. 8.22. Простановка соответствующих флажков позволяет: П подключить или отключить панель инструментов (Show toolbar (Показать панель)); П сделать более наглядной палитру компонентов, снабдив каждый интерфейсный элемент подписью (Show names in component palette (Отображать имена в палитре компонентов)); П отображать полные или укороченные имена файлов (Show file extension in window title (Отображать расширение файла), Show file path in window title (Отображать путь к файлу));
354 Глава 8 П фильтровать список имен файлов или показывать все файлы в диалоговых окнах (Show all files in file open dialog (Отображать все файлы)); П запрашивать подтверждение на запоминание файла интерфейса (Show save confirmation on activate (Отображать подтверждение сохранения файла)); П запрашивать подтверждение на запоминание файла при экспорте (Show save confirmation on export (Отображать подтверждение сохранения файла)). «Jt. Preferences ' 1+1-General Ijti-Fonts j~~Colors !=!-■ -Commend Window '—Keyboard & Indenting i—Command History 1+1 -Editor/Debugger i-Help —Web —Current Directory j —Workspace —Array Editor ] j-CTra j air-Figure Copy Template I Й-Slmullnk i i ■j ■s *'b ■;!';>;':K-':V''"0:";i ' .. * - GUIDE Preferences :, ' ... *"•' SWMtwftw^ яхшж&ешг rie» >*f-te " P Show toolbar P Show names fn component palette P Show file extension In window title Г" Show tile path In window title V Show all tiles in file open dialog P Show save contirmrflon on activate P Show save confirmation on export OK | Cancel НЕЮ •jfi Л T ■*!.-. * Jlfl} * 1 Apply | Help j Рис. 8.22. Предварительная настройка редактора GUIDE Редактор GUIDE вызывается командой guide из командного окна путем выполнения цепочки команд главного меню File | New | GUI (Файл | Создать | Графический интерфейс) или с помощью стандартной схемы запуска Start | MATLAB | GUIDE (GUI Builder) (Пуск | MATLAB | GUIDE (GUI Builder)). Две вкладки, присутствующие в стартовом окне (рис. 8.23), позволяют начать проектирование нового интерфейса (вкладка Create New GUI (Создать новый интерфейс)) или воспользоваться ранее созданным интерфейсом (вкладка Open Existing GUI (Открыть существующий интерфейс)). Дело в том, что описание формы приложения вместе с расположенными на ней интерфейс-
Проектирование интерфейса 355 ными компонентами может быть сохранено в файле с расширением fig. Если на диске хранится нечто похожее на наше будущее приложение, то существующим файлом можно воспользоваться с целью экономии времени. GUIDE Quick Start И CrealeNewGUi | Open Existing GUI ) "^^j" #)• ■" ""*""***" '' :i' Preview*——■■—■ — ■■■- : — -rnvj BUNK Г Save on startup as: iHtMATi^rivvoitturiKiedl.lki Browse,.' OK I Cencel Help Рис. 8.23. Начальное окно GUIDE Список шаблонов (GUIDE templates) предлагает четыре варианта компоновки, которые можно положить в основу проектируемого приложения: □ Blank GUI (Default) (Шаблон интерфейса) — проект начинается с нуля и в нашем распоряжении оказывается пустая форма, на которой можно размещать любые интерфейсные элементы (uicontrois), поля графиков (axes), Главное И всплывающие меню (Main И Popup Menu); □ GUI with Uicontrois (Типовой интерфейс) — в качестве прототипа предлагается готовое к исполнению несложное приложение, содержащее 15 интерфейсных компонентов (окна ввода, метки, панели, кнопки, переключатели). В качестве результата работы оно выдает произведение двух физических величин — плотности и объема, значения которых пользователь вводит в соответствующих окнах. Исходный текст m-файла и Property Inspector (Инспектор свойств) позволяют "рассмотреть основные моменты, связанные с функционированием интерфейсных элементов, с программированием функций — обработчиков соответствующих событий, с реакцией на ввод ошибочных данных; WWIUL. LCIIipiCHCO -i Blank GUI (Default) <ф, GUI with Uicontrois ф. GUI with Axes and Menu ■ф. Modal Question Dialog
356 Глава 8 П GUI with Axes and Menu (Интерфейс с координатными осями и меню) — в качестве прототипа предлагается готовое к исполнению приложение, воспроизводящее график одной из шести функций в зависимости от выбранной строки раскрывающегося списка. Текст исходной программы также открыт для изучения техники использования поля графики и команд меню; П Modal Question Dialog (Модальное диалоговое окно) — в качестве прототипа предлагается приложение, использующее диалоговое окно, содержащее запрос, предполагающий два варианта ответа. Приведенный ниже список поможет вам разобраться со спецификой приложений, предлагаемых в качестве прототипов. D Приложение с интерфейсными компонентами (рие. 8.24). Это приложение предназначено для демонстрации техники ввода числовых значений плотности (окно с меткой Density (Плотность)) и объема (окно с меткой Volume (Объем)). По нажатию кнопки Calculations (Вычисления) производится вычисление произведения плотности d на объем v, результат отображается в окне с меткой Mass (Масса). В рамке с меткой Units (Единицы измерения) размещены два переключателя, с помощью которых выбирается одна из систем измерения физических величин — английская (фунты — lb, кубические дюймы — cu.in) или СИ (килограммы — kg, кубические метры — cu.m). При изменении системы измерения меняется содержимое меток text4, texts, text6. Попытка ввести нечисловое значение, например, Density=abc, вызывает диалоговое окно с сообщением об ошибке (рис. 8.25). textl text2 — text3 — radiogroup panel density (edit) text4 [Measures- -fDensityMI Volume(V): Mass(D*V): volume (edit) english si (radiobutton) (radiobutton) D Ib/cu.in 0 cu.ln 0 lb <— text5 mass i_ text6 (text) Units— ff English Unit'System r S.I. Unit System Calculate Reset pushbutton2 ■— pushbuttonl Рис. 8.24. Индикатор интерфейсных компонентов
Проектирование интерфейса 357 \'J> Error В n-lxj j Input must bea number OK " :4f ; Рис. 8.25. Реакция на ввод нечислового значения На рис. 8.26 приведено окно Object Browser (Просмотр объектов), в котором отражена информация обо всех объектах приложения. Object Browser НПО ЕН--Н figure (Untitled) —ЁнЗ uicontrol (calculate "Calculate") —ШП uicontrol (reset "Reset") EjH^] uipanel [uipenell "Measures") ■ami uicontrol (textl "Density(D):") im uicontrol (text2 "Volume (V):") № uicontrol (density "0") ■№" uicontrol (volume "0") -W uicontrol (юаяз "0"| -.™. uicontrol (text3 "Kass (D*V):") ftibuicontrol (taxt6 "lb") —ЭЧП uicontrol (text4 "ib/cu. m") wuicontrol (texts "cu.in") B- QS uitools.uibuttongroup (unitgroup "Units") ~в> uicontrol [english "English Unit System") —ф uicontrol (si "S.I. Unit System") I Л Рис. 8.26. Реестр объектов приложения П Приложение с графиком и меню (рис. 8.27). Для программистов, работавших в других визуальных средах, покажется непривычным то, что компонент, напоминающий раскрывающийся список, на самом деле является всплывающим меню с включенным свойством visible. Щелчок на его кнопке раскрывает строки меню, команды которого представлены на рис. 8.28. Щелчок по кнопке Update (Обновить) приводит к выполнению callback- функции, представленной в примере 8.22.
358 Глава 8 Sf untitled2.fig 0le Edit View Layout lools detp .о gs:h"! i.-Щт *■■ r. | & m&jQas*£'!'^" 1 4 Select S.Push Button ■a Slider ® Radio Button В Check Box WF Edit Text ч>' Stallc Text еэ Pop-up Menu JEllUsibox Ш Toggle Button |q{ Axes 1¾ Panel 1¾ Button Group s)f AilivaX Control plot(rand(5)) jj (jpdale ^\ axesl у/ LI ИПП - p Рис. 8.27. Приложение с графиком и меню •> untitled4 File Рис. 8.28. Раскрытое меню (тип Popup Menu)
Проектирование интерфейса 359 . Пример '8:ЩфаШЪлс^^у^йиищяЩбг1^М^а{0^^^ .^¾½¾¾^^¾1^^^ function pushbuttonl_Callback(hObject, eventdata, handles) % hObject - указатель на pushbuttonl (см. GCBO) % eventdata - резерв для будущих версий MATLAB % handles - структура с указателями на все компоненты (см. GUIDATA) axes(handles.axesl); % активизация поля графика cla,- % очистка поля графика % опрос индекса вьщелеинои команды вспльшающего меню popup_sel_index = get(handles.popupmenul, 'Value'); % переключатель по номеру выделенной команды switch popup_sel_index case 1 % построение ломаной по случайным координатам plot(rand(5)); case 2 % построение синусоиды plot(sin(1:0.01:25)),• case 3 % динамическое построение косинусоиды comet(cos (1:.01:10)); case 4 % построение столбцовой диаграммы bar(l:10); case 5 % построение сечений мембраны plot(membrane); case" б % построение поверхности surf(peaks); end ЯГ untitled3. fig 01ё Edit. View Layout Tpols (Help ИПП D G*-,JB I .& *i ft -J " | Ф В №> ' Q Й «£ j> I It Select И Push Button • Slider €> Radio Button И Check Box 5Ф7 Edit Text i" Static Text Do you want to create a question dialog? Yes ■ No Рис. 8.29. Приложение с диалоговым -запросом
360 Глава 8 Кроме всплывающего меню приложение снабжено главным меню с единственным разделом File (Файл), в состав которого включены три команды — Open (Открыть), Print (Печать) и Close (Закрыть). □ Приложение с диалоговым окном (рис. 8.29). ' Запуск этого приложения приводит к появлению диалогового окна, представленного на рис. 8.30. untitled5 f7\ 1 t l Do you want to create a question dialog? ■■ 4*4 Yes No ЕЭ Рис. 8.30. Запрос на создание диалогового окна 8.3.2. Управление конструктором графического интерфейса По умолчанию работу в конструкторе графического интерфейса (GUIDE) начинают с пустого приложения. В наше распоряжение предоставляется окно конструктора (в документации MATLAB его называют Layout Editor (Редактор компоновки) с пустой формой на рабочем поле (рис. 8.31). Заголовок конструктора снабжен именем будущего интерфейсного файла — untitled.fig (безымянный), которому перед записью на диск надо присвоить более содержательное название. У левой границы конструктора расположена однорядная палитра интерфейсных компонентов, снабженных подписями (на вкладке GIUDE Preference (Параметры конструктора графического интерфейса) был помечен режим Show names in component palette (Отображать имена в палитре компонентов) — см. рис. 8.22). Рабочее поле конструктора занято проектируемой формой, на которой нанесена вспомогательная сетка, обеспечивающая довольно простое выравнивание компонентов по узлам и линиям. Шаг сетки можно регулировать. Более точные цифровые размеры и положение компонента на форме можно будет задать в Property Inspector (Инспектор свойств). Редактор конструктора располагает собственным главным меню, разделы которого комментируются ниже.
Проектирование интерфейса 361 aflf untitled, fig File Edit View Layout Tools :d g?h'| r^e 1 «!-*b 1 It Select LsD Push Button =» Slider "® Radio Button В Check Box ''*" Edit Text .. 3«' Static Text ЕЭрор-up.Menu JELIstbox BBToggle Button IfiiAxes (¾ РапвГ (I*: Button Group s)f ActiveX control <l - Help НПО № ;'"0'Й'* !""• ■ ■_ ' ■!_ ! 1 '-■ . t )• 1' ж , —J J1 Рис. 8.31. Проектирование формы с нуля Список команд меню File (Файл) содержит довольно обычный набор процедур по созданию (New (Новый)), открытию (Open (Открыть)), закрытию (Close (Закрыть)) и сохранению (Save (Сохранить), Save As (Сохранить как)) интерфейсного файла. Команда Preference (Предпочтения) открывает окно по предварительной настройке параметров системы, которое уже рассматривалось в гл. 2. По команде Export (Экспорт) в текущем каталоге запоминается m-файл, включающий команды и функции по формированию графического окна с встроенными интерфейсными компонентами. Этот файл очень напоминает интерфейсный файл с расширением fig, и им можно воспользоваться в других приложениях. Пусть вас не смущают размеры экспортируемого файла. Например, для пустой формы untitled.fig соответствующий экспортируемый файл по умолчанию имеет имя untitled_export.m и содержит 315 строк. Большую часть этого файла составляют комментарии, описывающие использованные данные и функции. Команда Print (Печать) позволяет выдать на принтер сформированное окно. В нижней части меню File (Файл) запоминаются имена последних fig-файлов, с которыми работал пользователь, и это обеспечивает быстрый доступ к любому из них. Меню Edit (Правка) содержит достаточно известные процедуры по отказу от только что сделанного исправления (Undo (Отменить ввод)), возврату к отмененному исправлению (Redo (Повторить)), вырезанию (Cut (Вырезать)) или копированию (Сору (Копировать)) выделенного компонента или группы компонентов в буфер обмена (clipboard), по извлечению информации из
362 Глава 8 буфера обмена (Paste (Вставить)). Одиночный компонент на поле редактора выделяется щелчком мыши в тот момент, когда ее указатель находится над компонентом. Выделенный компонент отмечается небольшими квадратиками по углам габаритного прямоугольника. Для выделения нескольких компонентов надо нажать и удерживать клавишу <Shifl> и щелкать мышью по нужным элементам. С помощью команды Select All (Выделить все) можно выделить все интерфейсные элементы, установленные на форме. Выделенные компоненты удаляются с помощью клавиши <Delete> или команды Clear (Очистить). Команда Duplicate (Дублировать) используется для дублирования выделенного элемента, что обеспечивает идентичность большинства свойств у вновь созданного клона (габариты, надпись и т. п.). Меню View (Вид) обеспечивает вызов таких редакторов, как Property Inspector (Инспектор свойств), Object Browser (Просмотр объектов), M-file Editor (Редактор М-файлов). Команды Component Callbacks (Реакция на события от компонента) и Figure Callbacks (Реакция на события от графического окна) вызывают дополнительные меню для перехода в режим запоминания в формате m-файлов функций — обработчиков различных событий, относящихся к выделенному объекту. Меню Layout (Разметка) включает группу команд по перестановке объектов, загораживающих друг друга. По команде Bring to Front (Перенести на передний план) помеченный объект или группа объектов перемешаются на передний план, заслоняя собой непомеченные объекты. Команда Send to Back (Перенести на задний план) заставляет переместиться на задний план все помеченные объекты. Команды Bring Forward (Перенести вперед) и Send Backward (Перенести назад) отличаются тем, что перемещаемые ими объекты не совершают крайние движения — либо в начало, либо в конец, — а осуществляют свои перестановки только на один уровень. Это напоминает ситуацию, когда солдат, построенный в колонну по одному, меняется местами со своим ближайшим соседом спереди или сзади. Команда Snap to Grid (Привязать к сетке) включает или отключает режим, фиксирующий размещаемые компоненты на линиях и узлах вспомогательной сетки. Раздел Tools (Сервис) включает команды вызова инструментальных средств конструктора графического интерфейса: □ Align Objects (Выровнять объекты) — инструмент для управления положением интерфейсных объектов; П Grid and Rules (Сетка и линейки) — инструмент для управления сеткой и измерительными линейками; □ Menu Editor (Редактор меню) — редактор главного и всплывающего меню; □ Tab Order Options (Порядок табуляции) — инструмент для изменения порядка следования интерфейсных элементов при последовательных нажатиях клавиши <ТаЬ>.
Проектирование интерфейса 363 В этот же пункт меню включены команды по запуску сформированного приложения (Run (Запуск)) и настройке параметров, управляющих режимами работы конструктора (GUI Options (Опции интерфейса)). Окно GUI Options (Опции интерфейса), используемое для дополнительной настройки параметров конструктора графического интерфейса, приведено на рис. 8.32. GUI Options Resize behavior: - j Non-resizable Command-line accessibility:. 1 Callback (GUI becomes Current Fi С Generate FlG-file and M-lile (7 Generate callback function prototypes 17 GUI allows only one instance to run (singlelon) 17 Use system color scheme for background (recommended) (~ Generate FlG-file only Vi. .-, OK fi Sfb V 9ure within Callback '■w 4 Cancel £) Help " " ', E3 . Рис. 8.32. Настройка параметров редактора GUIDE Первый раскрывающийся список Resize behavior (Размеры окна) позволяет выбрать вариант поведения приложения при попытке пользователя изменить размеры окна. Возможных вариантов три: П Non-resizable (Размеры постоянны) — окно не допускает изменения своих размеров; □ Proportional (Пропорционально) — изменение размеров окна допускается и одновременно происходит автоматическое масштабирование всех компонентов, размещенных на форме; П User-specified (Задание пользователем) — изменение размеров окна допускается, но перекомпоновка всех интерфейсных элементов возлагается
364 Глава 8 на программу пользователя, реагирующую на событие Resize (свойство ResizeFcn является указателем на эту функцию). Раскрывающийся список Command-line accessibility (Доступ к командной строке) управляет разграничением доступа к указателю на текущую фигуру (gcf) между функциями GUI и командной строкой. Здесь выбор представлен чегырьмя вариантами: П Callback (Реакция на событие)) — функции обработки событий получают указатель на текущую фигуру; П Off (Отключить) — функции обработки событий никогда не получают указатель на текущую фигуру; П On (Включить) — функции графического интерфейса могут получить указатель на текущую фигуру из командной строки; П Other (Другие) — действуют установки, выполненные пользователем в Property Inspector (Инспектор свойств). На способ доступа к указателю на текущую фигуру влияют два свойства — HandleVisibility И IntegerHand]е. Первое из них может принимать одно из трех значений — on, off или Callback. Установка HandieVisibiiity=caiiback означает, что указатель на текущую фигуру доступен функциям обработки событий и функциям, которые вызываются из callback-обработчиков. Но для функций, вызванных из командной строки, указатель на текущую фигуру недоступен. Это защищает графический интерфейс от вмешательства со стороны пользователя. Установка HandieVisibiiity=off исключает указатель на текущую фигуру из списка доступных указателей (из структуры handles), и это налагает запрет на использование ряда Команд — xlabel, ylabel, zlabel, gca, gcf, findobj. В режиме Handievisibiiity=on указатель на текущую фигуру доступен любым функциям. Перевод свойства integerHandie в состояние off вынуждает MATLAB генерировать непредсказуемые вещественные значения указателей, что может предотвратить случайное нарушение функционирования графического объекта. Целочисленное значение указателя легко отобразить на экране и воспользоваться им для обращения к той или иной функции, изменяющей поведение объекта. Два переключателя позволяют выбрать один из режимов генерации интерфейсных файлов — только файл с расширением fig (Generate FIG-file only (Создать только fig-файл)) или оба файла с расширениями fig и m (Generate FIG-file and M-File (Создать fig- и m-файлы)). В последнем варианте имеется возможность задания любой комбинации следующих параметров: П Generate callback function prototypes (Создать прототипы функций реакции на событие) — генерировать прототипы саНЬаск^функций;
Проектирование интерфейса 365 П GUI allows only one instance to run (singleton) (Запуск одной копии приложения) — интерфейс допускает запуск единственного приложения (т. е. одновременное функционирование двух копий приложения запрещено); □ Use system color scheme for background (recommended) (Использовать в качестве фона цветовую схему системы (рекомендуется)) — использовать для фона цветовую установку системы. Режим генерации прототипов Callback-функций обеспечивает вставку в интерфейсные файлы заготовок для программирования обработчиков всех событий, связанных с размещенными на форме компонентами. Эти вставки снабжены подробными комментариями по поводу смысла параметров и назначения соответствующих функций. Меню Help (Справка) содержит две команды, вызывающие цепочку кадров со справочной информацией по вопросу использования конструктора интерфейса (Using the Layout Editor (Использование редактора компоновки)) и технологии создания графического интерфейса (Creating GUIs (Создание графического интерфейса)). Под главным меню расположена панель инструментов (рис. 8.33), на которой представлены кнопки быстрого запуска наиболее часто используемых команд. г Cut г Copy - Paste - Align Objects " Menu Editor г Tab Order Editor Run - dj^jbJ ^j4j®j^J_^|^Jjgj№]|s]a]^J|iiJ - Save -Open - Redo l-Undo - New M-file Editor - Property Inspector- О 3jec ЛВгс ws ar J Рис. 8.33. Панель инструментов конструктора графического интерфейса 8.3.3. Размещение интерфейсных элементов Выделим в палитре компонентов интересующий нас интерфейсный элемент и переведем курсор мыши в точку формы, соответствующую левой верхней
366 Глава 8 точке компонента. Теперь нам предоставляются две возможности. Во- первых, после щелчка на форме появляется выбранный интерфейсный компонент стандартных размеров. Во-вторых, можно нажать левую кнопку мыши и растянуть компонент до нужных размеров. Когда кнопка мыши отпускается, размеры элемента будут зафиксированы. Как правило, выбранный компонент прижимается к линиям координатной сетки, если соответствующий режим, действующий по умолчанию, не был отменен (см. команду Layout | Snap to Grid (Разметка | Режим сетки)). Компонент, попавший на форму, можно переместить. Для этого надо щелкнуть по компоненту (выделить его), после чего по углам выделенного компонента появляются небольшие квадратики. Затем зажимают левую кнопку мыши, и элемент перетаскивают на новое место. Если зацепиться указателем мыши за любой из выделенных уголков, то его размеры можно изменить вручную. Если по тем или иным причинам нас не устраивают положение и размеры выделенного компонента, то можно прибегнуть к услугам Property Inspector (Инспектор свойств). Если свойство Position "закрыто" (слева в квадратике виден знак +), то его надо "раскрыть", щелкнув по знаку. Затем в поле значений свойств можно изменить координаты точки привязки (х, у), ширину (width) или высоту (height) объекта (рис. 8.34). .... _- ■rjl- Position — X „у -width 1— height [14,143 28,25 21,571 1,5] 14.143 28.25 21.571 1.5 Рис. 8.34. Изменение позиции и размеров кнопки Компонент, попавший на форму по ошибке, можно удалить. Для этого его нужно выделить и нажать клавишу <Delete>. Для размещения на форме следующего компонента такого же типа и таких же размеров надо выделить элемент-прототип и выполнить команду Edit | Duplicate (Правка | Дублировать) — рис. 8.35. Над выделенным компонентом появится клон, который можно отбуксировать на нужное место. Вторая возможность создания клона существующего на форме компонента связана с использованием буфера обмена. Выделенный элемент копируется в буфер обмена (Edit | Сору (Правка | Копировать)), а затем по команде Edit | Paste (Правка | Вставить) вставляется один или несколько раз.
Проектирование интерфейса 367 Edit Undo Ctrl+2 Redo ОгГ+Л '"' Cut Ctrl+X Ccpy Ctrl+C Paste Ctrl+V Clear Select All Ctrl+A | Duplicate Ctrl+D ■' Push Г •" . ■>" Button " ■ 1 ■ ~ 1 p ■ Рис. 8.35. Создание клона Визуальное размещение и выравнивание нескольких элементов на форме облегчается за счет использования измерительных линеек и механизма выравнивания. После выполнения команды Tools | Grid and Rulers (Сервис | Сетка и линейки) на экране появляется вспомогательное меню (рис. 8.36). В нем можно отметить следующие средства выравнивания: П показать измерительные линейки (Show rulers (Отображать линии)); П показать направляющие линии (Show guides (Отображать направляющие линии)); П показать сетку (Show grid (Отображать сетку)). Ql- «I'll» " 8- # ■Л" (Я- so 100 «♦JkGrid an . ■Р" Show rulers P Show guides P Show grid - Grid Size (in Pixels): W Snap to grid it OK L50 200 250 1 1 Ш^^^^^Н* 60 i 70 80 90 ЕЕ^К. | Cancel | 1 1 1 1 _ 1 - ^- Рис. 8.36. Управление линейками и сеткой
368 Глава 8 Измерительные линейки, которые появляются на левой и верхней границах формы, снабжены цифровыми метками, позволяющими более точно выбирать положение интерфейсных компонентов. Шаг сетки можно регулировать с точностью до пиксела или выбирать из раскрывающегося списка. Команда выравнивания Align Objects (Выровнять объекты) вызывается из меню Tools (Сервис) или с помощью аналогичной кнопки на панели инструментов (рис. 8.37). Push Button Push Button Push Button 'Jk.Align Objects Vertical -^- '■ —^ Allgn Distribute Г Setspacncpor;i>-£l? В o3 Eps S* Ща S3 qQb §3 •Horizontal ■ Align ' . Distribute Г" г:.ц\ sflacina | p& § 4 ip|tp ^ 03' 20 nwelf OK Apply Cancel Рис. 8.37. Окно команды выравнивания компонентов Перед вызовом команды выравнивания следует выделить выравниваемые компоненты. Сделать это можно двумя способами — либо обвести контурным прямоугольником при нажатой левой кнопке мыши (рис. 8.38), либо нажать и удерживать клавишу <Shift> и щелкать мышью по нужным компонентам. Выравнивание выделенных компонентов производится либо по вертикали (см. группу Vertical (Вертикально) на рис. 8.37), либо по горизонт&чи (см. группу Horizontal (Горизонтально) на рис. 8.37). Утилита позволяет выровнять положение компонентов по любой из границ или по центру (для выбора варианта воспользуйтесь рисунком на кнопках), если будет сделан щелчок по одной из кнопок ряда Align (Выровнять) и нажата кнопка Apply (Применить). На рис. 8.39 показано расположение кнопок до выравнивания, а на рис. 8.40 — после выравнивания по левой границе. Приведенный пример демонстрирует, что в качестве границы при выравнивании влево выбирается компонент, расположенный левее всех. При выравнивании вправо
Проектирование интерфейса 369 ведущим становится элемент с самой правой границей, а при выравнивании по центру выбирается ось, расположенная между центрами самого левого и самого правого элемента. • : Push Button | 1 m m Push Button 1 ■ Push Button -- J i г ~ г 1 Рис, 8.38. Выделение компонент Push Button - ' ■ - Push Button [ 1 . Pu ■ ■Pt sh Button [ ■' «/.Align Objects РШЦиДЕЩ 1 я— Align off Distribute Г ЙР-tEPilUn ^ „Ли HJ ]? № u~l □-* rJL Si pi№it. i Hurlzuntal ;■'-.' -. . Alien off Г- T:?! Fp.ii-;»' w а|эо" p 2? -"■ I § Щ? 31 49 |>i?*fS СЖЛ Apply Cancel Рис. 8.39. Кнопки до выравнивания Кнопки ряда Distribute (Распределить) позволяют задать расстояние между соответствующими границами выделенных компонентов. Для выполнения этой операции следует поставить флажок Set spacing (Установить интервал), а затем в поле ввода справа задать величину смещения между компонентами. Кнопки OFF (Выключить) используются для сброса установленных режимов.
370 Глава 8 Push Button Push Button Push Button «JkAlign Objects Vertical — *■ - Align off ЧР Distribute ^3 In-1 St ! Г fiolii'iaarnipij fufAb Horizontal - Align Distribute OFF P -ft IP £P IP -¾ 49 Г Set-ipStingpO ' pixels ■OK - l| '' 'Apply Cancel Рис. 8.40. Кнопки после выравнивания по левой границе Направляющие линии, к которым можно "приклеить" интерфейсные компоненты, проводятся следующим образом. Наведите курсор на вертикальную или горизонтальную измерительную линейку, при этом курсор превратится в двунаправленную стрелку. Если нажать левую кнопку и начать перемещать мышь, то вслед за ней потянется вертикальная или горизонтальная прямая синего цвета. Захватив мышью нужный интерфейсный компонент, его перемешают до контакта с направляющей линией. Несмотря на режим Snap to Grid (Привязать к сетке), перемещаемые компоненты "приклеиваются" к направляющей линии, которая не обязана проходить через узлы сетки (рис. 8.41). »' •О О». * # s- ..I.1 0 1 1С 1 " _ Push Button I Push Button 1 1 Push Button ■ 1 1 • 0 Рис. 8.41. Выравнивание по направляющим
Проектирование интерфейса 371 8.3.4. Инспектор свойств (Property Inspector) Инспектор свойств вызывается по команде View | Property Inspector (Вид | Инспектор свойств) или с помощью соответствующей кнопки на панели инструментов. В левой половине раскрывающегося окна находится список свойств выделенного объекта, а в правой половине — их значения (рис. 8.42). При отсутствии выделенной фигуры в окне инспектора отображаются свойства фигуры. if untitled. Eile Edit Mlew fig Layout. Iools gj Property Inspector ЕЮЕЭ1 I И uloontiolCl>ltsM>uHon14"Push Button") d csa! * ъ.е. i^|*ifi | ^ Select CD Push Button ш» Slider ® Radio Button Й Check Box №EdilText m- Static Text ЕЭ Pop-up Menu MLIstbex ES Toggle Button fc^Axes ®j Panel lra Button Group !=Jf ActiveX Control id' 3" to ' ex- V ft- j ш 0 1 'I _ Push Button ■ - - *- BackgroundColor <5|| 1 * — BelngDeleted jff — BusyActlor j»j queue — ButtonDownFcn -CDala Щ, — Callback «.automatic — Clipping _~j on -- CreateFcn — DeleteFcn — Enable j»J on 4-Extent 10 0 10.857 11 -FontAngle *\ normal — FontName MS Sans Serif — FontSire 8.0 — FontUnits ^j points - FontWeight vj normal f- ForegroundColor ®] |^Щ^Ц f- HanaieVlslblllly _V| on |—HilTesl _vjon 1— HorlzontalAllanment -w\ center jd <l 1 >"l Рис. 8.42. Инспектор свойств (выделена кнопка типа Push Button) Если левее названия свойства виден небольшой квадратик, то значением свойства является вектор, и доступ к его отдельным компонентам возможен только тогда, когда свойство "раскрывается". Раскрытому свойству соответствует знак — в квадратике. Знаки + и — сменяют друг друга при последовательных щелчках по квадратику. Наличие кнопки с черным треугольником в правой половине позволяет выбрать значение свойства из раскрывающегося списка. Кнопка, содержащая кружок с тремя цветными секторами, вызывает стандартное окно выбора цвета из предлагаемой палитры. На поле значений свойств можно обнаружить еще одну кнопку, на поверхность которой нане-
372 Глава 8 сен квадратик размером 3x3 с желтыми точками. Значение соответствующего свойства представлено .матрицей той или иной размерности. Основное назначение Property Inspector (Инспеюор свойств) — выполнять на стадии проектирования приложения в среде GUIDE те же самые действия, которые реализуют функции get и set во время работы приложения, т. е. просматривать текущие значения интересующих нас свойств или заменять их новыми значениями. 8.3.5. Просмотр объектов (Object Browser) Вызов браузера объектов (рис. S.43), расположенных на форме, осуществляется командой View | Object Browser (Вид | Просмотр объектов) или щелчком по соответствующей кнопке на панели инструментов. Гя Object Browser НПО Push Button *~ Radio Button Fl ¢3 figure (Untitled) —И uicontrol (pushbutton^ "Push Button") <•) uicontrol (radiobuttonl "Radio Button") Рис. 8.43. Браузер объектов В окне браузера отображается дерево объектов в порядке их размещения на форме. Подчиненность ветвей дерева соответствует взаимоотношениям между объектами-родителями (parent) и объектами-потомками (chidren). Такого рода просмотр может представить интерес при изучении чужой программы. 8.3.6. Создание меню (Menu Editor) Редактор меню (рис. 8.44) имеет две вкладки в нижней части, переключая которые, можно создавать либо главное (Menu Ваг (Панель меню)), либо всплывающие (Context Menus (Контекстные меню)) меню. Работа по созданию меню начинается со щелчка по одной из кнопок: New Menu (Новое меню) или New Context Menu (Новое контекстное меню). Предположим, что мы решили создать нестандартное главное меню для программы решения квадратного уравнения. Пусть первый пункт меню Подготовка содержит три команды — Ввод а. Ввод b и Ввод с. Во втором пункте меню Решение разместим четыре команды — Найти корни, Построить график, Разделительная черта и Выход.
Проектирование интерфейса 373 New Menu New Menu Item New Context Menu Move Backward Selected Item Move Forward , Move Down Selected Item ^ Selected Item Move Up "Selected Item *ДМ«гш Editor glift -fe 1; ♦—=* i Delete Selected Item Menu Bar 1 Context Menus Properties i INoihlnoselectea. ъ Help Рис. 8.44. Кнопки управления редактором меню Выберем вкладку Menu Ваг (Панель меню) и щелкнем по кнопке New Menu (Новое меню). Содержимое окна редактора мгновенно изменится (рис. 8.45). В левой части появился пока безымянный раздел untitled 1, а в правой — основные свойства этого объекта (UIMenu Properties (Свойства объекта меню)): □ поле Label (Метка), содержащее название раздела (пока untitled 1); □ поле Tag (Ярлык), в котором отображается имя указателя на объект; П раскрывающийся список Accelerator: Ctrl + (Клавиша быстрого вызова), с помощью такого сочетания клавиш можно быстро вызвать меню или команду меню; П флажок Separator above this item (Разделитель перед командой), позволяющий включить в меню строку-разделитель перед формируемой командой; □ флажок Check mark this item (Пометить команду), позволяющий поставить галочку перед названием команды; П флажок Enable this item (Разрешить этот пункт), сброс флажка меняет его окраску и блокирует выполнение соответствующих команд; □ поле Callback (Реакция на событие), предназначенное для связи формируемой команды с callback-функцией обработки щелчка по наименованию команды.
374 Глава 8 «•Л Menu Editor НПО В •*« Ш ■:;♦*• -* t 1 i 9 - -ШпИЯПИП i- i i i" Menu Bar Context Menus | -y Label: |unfflled 1 Tag; (UntitledJ Accelerator: Ctrl +j None J^j Г" Separator above this Sem Г Check mark this Hem 17 Enable this Item .CaHback:|%eutomatic View | ■ ■ OK 1 Help | Рис. 8.45. Начало формирования главного меню Заменим содержимое поля Label (Метка) на название нашего раздела и содержимое поля Tag (Ярлык) на более осмысленное имя указателя — input (рис. 8.46). *„ifeMenu Editor Б >=* Ш | ♦- т+ t J. | О -в Menu Bar Context Menus -UIMenu Properties—т •——■ Label: (Подготовка Tag: |lnput| Accelerator: Ctrl +1 None Г* Separator above this Sem Г" Check mark this item Г? Enable this Bern Callback: r&autornatic .. OK | d 1 View |: Help Рис. 8.46. Формирование первой команды
Проектирование интерфейса 375 Теперь займемся формированием первой команды первого раздела: 1. Щелкнем по кнопке New Menu Item (Новая команда меню), и в окне появится первая, пока неименованная, команда (untitled 2). 2. Выделим щелчком первую команду. 3. Заменим ее название на "Ввод а", а значение свойства Tag (Ярлык) на Input_a. Для формирования следующей команды первого раздела сначала выделим раздел Подготовка и только потом щелкнем на кнопке New Menu Item (Новая команда меню). В противном случае вновь создаваемая команда окажется подкомандой первой команды (т. е. командой меню следующего уровня). Выделим вторую команду и заменим значения ее свойств Label (Метка) и Tag (Ярлык). Снова выделим раздел Подготовка и щелкнем по кнопке New Menu Item (Новая команда меню). Выделим третью команду и заменим значения ее свойств Label (Метка) и Tag (Ярлык). Для формирования меню Решение щелкнем на кнопке New Menu (Новое меню), выделим новый раздел и сформируем значения его свойств Label (Метка) и Tag (Ярлык). По описанной ранее схеме создадим команды второго раздела. Единственная особенность формирования команды Выход заключается в том, что перед ней необходимо вставить разделительную черту (рис. 8.47). «■ДМетш Editor й *-■ ti I«• ■ ► : НПО f- Ц] Подготовка *** Ввод а ** Ввод b "— ►=! Ввод С Э- Ц] Решение М Найти корни ия Построить график Menu Bar | Context Menus ■UIMenu Properties - (Label: |Выхоя | Tag: |Exit Accelerator: Ctrl +| None I*7 isB§^sr_Ste!SU!!£Jteffil Г" Check mark this Item; W Enable this Item .Callback: %automatic ~3 OK View ..- Help Рис. 8.47. Формирование последней команды меню Решение 11 Зак. S99
376 Глава 8 Прежде чем привязывать к командам меню функции — обработчики события callback, убедимся в том, что сформированное нами меню соответствует замыслу. Для этого попробуем выполнить созданное приложение, нажав кнопку Run (Запуск). Система тут же предложит запомнить файлы с описанием приложения (т- и fig-файлы), выдав окно, представленное на рис. 8.48. Если файлы с такими именами уже присутствуют в рабочем каталоге, то будет выдано еще одно предупреждение (рис. 8.49). Оно предлагает на выбор две возможности — либо заменить предыдущие описания новыми (кнопка Replace (Заменить)), либо объединить их в одно (кнопка Append (Добавить)). После ответа на предложения системы на экране появляется приложение с нашим меню, проверка разделов которого подтверждает правильность наших действий (рис. 8.50). [ЗШЗЗ Q в ? у Activating will save changes to yourfigure and M-flle. Do you wish to continue? -^- F Do not show this dialog again. I ¥?s._ " ho ■ Рис. 8.48. Предложение сохранить файлы GUIDE ЕЗ А File: H:\MATLAB7\wortountitled.rri already exists, Do you want to replace It or append to it? [„.Replace Append | Cancel | Рис. 8.49. Предложение заменить или добавить файлы |-> roots4 | Подготовка Ввода ВвбдЬ Вводе Решение |лА roots4 Подготовка j Решение Найти корни Построить график ' Выход Рис. 8.50. Внешний вид меню
Проектирование интерфейса 377 При формировании меню возможны ошибки, иногда появляется желание перекомпоновать последовательность команд, удалить лишние команды. Для этой цели можно воспользоваться набором кнопок на панели Menu Editor (Редактор меню) (см. рис. 8.44). Их действие распространяется только на выделенную команду или выделенный раздел. Четыре кнопки-стрелки позволяют переместить выделенный элемент (Move Forward Selected Item (Переместить выделенный элемент вперед), Move Backward Selected Item (Переместить выделенный элемент назад), Move Up Selected Item (Переместить выделенный элемент вверх), Move Down Selected Item (Переместить выделенный элемент вниз)). Последняя кнопка на панели редактора меню (Delete Selected Item) удаляет выделенный элемент. Проектирование всплывающего меню имеет небольшие особенности. Во- первых, у него отсутствует явное название раздела, и поэтому в начальной заставке (рис. 8.51) нет поля значения для свойства Label. Во-вторых, всплывающее меню должно быть привязано к конкретному объекту. Поэтому после создания всплывающего меню его указатель (значение свойства Tag) должен быть занесен в значение свойства uicontextMenu ассоциированного объекта. Создание всплывающего меню начинается с выбора вкладки Context Menus (Контекстные меню). После щелчка по кнопке New Context Menu (Новое контекстное меню) -в левой части окна редактора меню появляется указатель контекстного меню с очередным системным именем untitied_jc. Перед заменой этого указателя более содержательным наименованием необходимо щелкнуть по системному имени, после чего в правой части окна редактора появится поле для изменения значения свойства Tag (Ярлык) — рис. 8.51. Формирование команд всплывающего меню происходит по описанной выше схеме: 1. Нажимаем кнопку New Menu Item (Новая команда меню). 2. Выделяем указатель (название) очередной команды в левой части окна. 3. Изменяем значения ее свойств Label (Метка) и Tag (Ярлык). 4. Выделяем указатель (название) меню в левой части окна. 5. Повторяем пункты 1—4 для подключения следующей команды. В качестве примера приведем вид последнего окна редактора (рис. 8.52), в котором сформировано всплывающее меню с указателем eolorbutton. После создания всплывающего меню его надо привязать к объекту — кнопке типа Push Button, которая будет менять цвет фона при щелчках по командам меню. Для этого необходимо выделить ассоциированный объект, вызвать окно Property Editor (Инспектор свойств), щелкнуть по стрелке свойства urcontexuMenu и выбрать указатель на созданное меню (рис. 8.53).
378 Глава 8 «jtMenu Editor НПЕЗ -:1йИШ13!11 Menu Bar Context Menus |Tag: |untitled_1 Callbeclcj%automatic View I More options » | f J. OK | Help ■ I Рис. 8.51. Начальная заставка для формирования контекстного меню да&Мегш Editor f] ~ Ш I - ■ ► ? £ НПО I color_tsutton -^ красный - *и зеленый Menu Bar context Menus UIMenu Properties Label |c Teg: |blue_button Г" Separator above this Hem I- Check mark this item R Enable this item Callback: %automalic View More options » OK •Help Рис. 8.52. Завершение формирования контекстного меню
Проектирование интерфейса 379 ^Property Inspector H|~1F3 H uloontrol (pushbutton! "Pujh Button") so 10( Push Bu >— HltTest HorizontalAltsnment Interruptlfcle KeyPriessFcn — LlstboxTop — Max -Mln |фг— Position SelectlonHigtilight Д- SllderStep — String Style Tas Tooltip String UlContexIMenu Units UserData —Value, Visible •И center ■«•Ion 1.0 1.0 0.0 (5 28.0516,429 2.6] ▼Jon (0,01 0,1] JF| Push Button ▼| pushbutton pushburlonl I""" <None> H I Ml ^ со|ш-Ьийоп If d< Рис. 8.53. Связывание всплывающего меню с объектом После выполнения указанных мероприятий запустим приложение, нажав кнопку Run (Запуск), и удостоверимся, что при щелчке правой кнопкой мыши на объекте типа Push Button появляется спроектированное меню (рис. 8.54). •> untitled7 Push Button красны?! зеленый синий Рис. 8.54. Всплывающее меню для кнопки типа Push Button Формируя главное или контекстное меню, мы до сих пор не связывали щелчки по командам меню с функциями — обработчиками события
380 Глава 8 callback. В следующем разделе рассматриваются стандартные соглашения MATLAB 7 по поводу организации таких обработчиков. 8.3.7. Анатомия файла, создаваемого в среде GUIDE Для того чтобы разобраться в структуре данных и методах, автоматически формируемых средой GUIDE при создании интерфейсного файла, реконструируем пример с двумя кнопками типа push Button, описанный в разд. 8.1.1. Разместим в графическом окне кнопку типа Push Button, подберем ориентировочно ее размеры и положение. Редактор GUIDE автоматически формирует у этой кнопки значения свойств Tag, string и Position. Значения этих свойств для выделенной кнопки можно рассмотреть и, если понадобится, изменить с помощью Property Editor (Инспектор свойств) — рис. 8.55. Заменим значение свойства string на строку кнопка!. Г-"ft.; ШЫ"- File Edit; \1\ъщ f i г UsjJout To: Di^@;.Ji Ш т <" | ^ Select GEO Push Button «™ Slider Ф Radio Button 0 Check Box * EditTexl ™< Static Text еэ Pop-up Menu 2- 3- s " '■"■! IP ««I « в p j a e 0 1 0 ISO 20 _ Кнопка1 f Wj£ Property Inspector НВЕЗ HO ulcontrol (pushbuttonl "KHontjV') 1 - HifTest — HoiizonlalWIgrment j - InterrupllDle 1 - KeyFressFcn -ListbcxTop J -Max | -Mln a- Position ~- SelectionHiglllight ji- SllderStep ! Slrinti '"1 ж » ■w on center on 1.D 1.0 0.0 17 24,6 21,429 2,551 ▼Ion 10.01 0,1] Ш] Кноша1 I d ■ f> Рис. 8.55. Смена надписи на кнопке Создадим копию кнопки и присвоим ее свойству string значение кнопкаг. Пока мы не предусмотрели никаких действий по обработке событий callback для использованных интерфейсных элементов. Однако попробуем выполнить это пока еще незавершенное приложение — нажмем кнопку Run (Запуск). Перед запуском приложения нам предложат запомнить файлы, автоматически построенные конструктором графического интерфейса. Наберем в появившемся окне имя twobutton, после чего на фоне файла twobutton.m мы увидим окно нашего приложения с двумя кнопками Если заглянуть в рабо-
Проектирование интерфейса 381 чий каталог, то мы увидим два файла с названиями twobutton.fig и twobutton.m. Первый из них описывает окно и интерфейсные элементы нашего приложения в двоичном формате, поэтому разглядеть в нем что-то содержательное не удастся. Зато второй представляет обычный m-файл системы MATLAB, и его содержимое следует пристально изучить. В примере 8.23 приведена распечатка этого файла. Номера строк, предшествующие операторам, не являются элементами программы. Они вставлены только с целью приведения в соответствие наших комментариев и строк программы. Пусть вас не пугает длина m-файла, большая часть его строк представляет подробный комментарий. {'Пример;8.ж/Ф^^мюЬШопТт ','№•*$^-¾¾^¾ :-, ^W. »^ ^^^^^/Ш. \ 1 function varargout = twobutton(varargin) 2 % TWOBUTTON м-file for twobutton.fig 3 % TWOBUTTON, by itself, creates a new TWOBUTTON or raises 4 % the existing singleton*. 5 % H = TWOBUTTON returns the handle to a new TWOBUTTON or 6 % the handle to the existing singleton*. 7 % 8 % TWOBUTTON('CALLBACK',hObject,eventData,handles,...) calls 9 % the- local function named CALLBACK in TWOBUTTON.M with 10. % the given input arguments. 11 % 12 % TWOBUTTON('Property','Value',...) creates a new 13 % TWOBUTTON or- raises the existing singleton*. 14 % Starting from the left, property value pairs are applied 15 % to the GUI before twobutton_OpeningFunction gets called. 16 % An unrecognized property name ox invalid value makes 17 % property application stop. All inputs are passed to 18 % twobutton_OpeningFcn via varargin. 19 S 20 % *See GUI Options on GUIDE'S Tools menu. 21 % Choose "GUI allows only one instance to run {singleton)". 22 % 23 % See also: GUIDE, GUIDATA, GUIHANDLES- 24 25 % Edit the above text to modify the response to help twobutton 26 27 % Last Modified by GUIDE v2.5 09-Apr-2003 21:43:4В
382 Глава 8 28 29 % Begin initialization code - DO NOT EDIT 30 gui_Singleton = 1; 31 gui_State = struct['gui_Name', mfilename, ... 32 'gui_Singleton', gui_Singleton, ... 33 'gui_OpeningFcn', Gtwobutton_OpeningFcn, ... 34 'gui_OutputFcn', Gtwobutton_OutputFcn, ... 35 'guiJ^ayoutFcn', [] , ... 36 'gui_Callback\ []),- 37 if nargin & isstr(varargin!1}) 38 gui_State.gui_Callback = str2func(varargin(l}); 39 end 40 41 if nargout 42 [varargout(l:nargout}] = guijnainfcn(gui_State, varargin(:}); 43 else 44 guijisinfcn(gui_State, varargin{:)); 45 -end 46 % End initialization code - DO NOT EDIT 47 49 49% Executes just before twobutton is made visible. 50 function twobutton_OpeningFcn(hObject, eventdata,... 51 handles, varargin) 52 %-■ This function has no output args, see DutputFcn. 53 % hObject handle to figure 54 % eventdata reserved - to be defined in a future version of MATLAB 55 %■ handles structure with handles and user data (see .GUIDATA) 56 % varargin command line arguments to twobutton (see VARARGIN) .57 58 % Choose default command line output for twobutton 59 handles. output = hObject; 60 61 % Update handles structure 62 guidata(hobjeer, handles); 63 64 % UIWAIT makes twobutton wait for user response (see UIRESUME) 65 % uiwait(handles.figurel);
Проектирование интерфейса 383 66 6-7 % Outputs from this function are returned to the command line. 68 function varargout = twobutton_OutputFcn(hObject,... 69 eventdata, handles) 70 % varargout cell array for returning output args (see VARARGOUT}; 71 % hObject handle to figure 72 % eventdata reserved - to be defined in a future version of MATLAB 73 % handles structure with handles and user data (see GUIDATA) 74 75 % Get default command line output from handles structure 76 varargout{1J = handles.output; 77 78 79 % Executes on button press in pushbuttonl. SO function pushbuttonl_Callback(hObject, eventdata, handles) 81 % hObject handle to pushbuctonl (see GCBO) 82 % eventdata reserved - to be defined in a. future version of MATLAB 83 % handles structure with handles and user data (see GUIDATA) 84 85 % Executes on button press in pushbutton2. 86 function pushbutton2_Callback(hObject, eventdata, handles) 87 % hObject handle to pushbutcon2 (see GCBO) 88 % eventdata reserved - to be defined in a future version of MATLAB 89 %. handles structure with handles and user data (see GUIDATA) Строка 1 — это заголовок нашей функции. У нее предусмотрен один входной аргумент, представленный массивом ячеек varargin (см. разд. 4.6), и один выходной аргумент, в роли которого выступает массив ячеек varargout. Это предоставляет нам возможность вызывать из командной строки наше приложение разными способами: » twobutton » hftpp= "twobutton » twobutton('Position',[10 10 250 200]) » twobutton(xl,x2,x3) » [yl у2] = cwobutton(...) Пока мы не планировали никаких входных и выходных параметров для нашей функции, но в будущем они могут пригодиться. Второй вариант вызова возвращает указатель на наше приложение после завершения его работы. Третий вариант обращения, который содержит допустимое для фигуры
384 Глава 8 свойство Position и его конкретное значение, может заставить окно нашего приложения появиться в заданной точке экрана и трансформировать свои размеры до указанных ширины и высоты. Четвертый вариант передаст нашему приложению значения аргументов xi, х2 и хз как ячейки varargin{i}, varargin{2) и varargin{3). В пятом варианте вызова запланирован возврат выходных параметров, в роли которых выступят сформированные приложением значения ячеек varargout{l} и varargout(2}. Строки 2—25 представляют собой комментарий, дословный перевод которого мы приводим ниже: 2 % TWOBUTTON представляет m-файл для twobutton.fig 3 % TWOBUTTON без параметров создает новое приложение или продолжает 4 % выполнение существующего одиночного приложения. 5 1 Н = TWOBUTTON возвращает указатель на новое 6 % или существующее приложение. 7 % 8 % TWOBUTTON('CALLBACK',hObject,eventData,handles,...) вызывает 9- % локальную подфункцию с именем CALLBACK 10 % и передает ей указанный список входных аргументов. 11 % 12 % TWOBUTTON('Property','Value',...) создает новое 13 % приложение или продолжает выполнение существующего приложения. 14 % Перед стартом приложения вызывается функция twobutton_OpeningFunction, 15 % которой передаются, пары параметров ("свойство — значение"). 16 % Если параметр Property не является названием свойства или заданное значение 17 % Value- недопустимо, то приложение не запускается. Все входные параметры 18 % функции T:wobucton_OpeningFunction передаются ей через varargin. 19 % 20 % См. GUI Options в меню Tools (Сервис). 21 % Выбрано "GUI допускает выполнение единственного приложения (singleton)". 2.2 % 23 % См. также GUIDE, GUIDATA, GUIHANDLES 24 % 25 % Отредактируй приведенный выше текст, включив в него информацию для справки. В строках 29—46 располагаются команды инициализации приложения, и менять в этих строках ничего нельзя. Здесь устанавливается монопольный
Проектирование интерфейса 385 режим работы приложения (singieton=i), создается структура состояния приложения (gui_state) и заполняются ее поля. Если при вызове приложения были указаны входные параметры (nargin>o), то строка с их списком переносится в массив ячеек varargin и корректируется соответствующее поле в структуре gui_state. Затем производится обработка списка выходных аргументов, если таковой присутствовал в команде вызова приложения. Строки 49—65 занимает так называемая "открывающая" функция со стандартным именем xxxOpeningFcn (в каждом конкретном приложении символы ххх заменяются именем m-файла) и фиксированным списком аргументов — {hObject, eventdata, handles, varargin). Эта функция работает один раз перед тем, как окно приложения появится на экране монитора (аналог обработчика события onCreate в системах ВСВ, Delphi), однако ей доступны указатели на все интерфейсные элементы, расположенные на форме. И в этой функции можно произвести изменения тех или иных свойств фигуры и ее компонентов. Входные аргументы "открывающей" функции имеют следующий смысл: П hobject — указатель на фигуру (окно приложения); О eventdata — пустой аргумент, зарезервированный на будущее; □ handles — структура, содержащая ноля с указателями на все интерфейсные элементы, установленные на фигуре (в нашем примере таковыми являются указатели handles.pushbuttonl И handles.pushbutton2); □ varargin — массив ячеек, который либо пуст, либо хранит значения входных аргументов, заданных в командной строке. Особое внимание следует обратить на структуру handles. Изначально она создается системой с помощью функции guihandies: handles = guihandies(hObject); Эта структура передается всем обработчикам событий (callback-функциям) и доступна всем подфункциям, включенным в GUI-файл. Любая функция может добавить к этой структуре новое поле, например, с именем name_f ield, и сформировать там нужное значение (value): handles.name_field = value; Для того чтобы новое поле стало доступным другим функциям или функции-создателю, когда к ней обратятся повторно, содержимое обновленной структуры надо сохранить в укромном месте: % запоминание структуры в "памяти" фигуры guidata(hObject, handles.) ; % запоминание структуры- в "памяти" СаНЬаск-объекта guidata(gebo, handles);
386 Глава 8 Если функция не получает структуру handles в качестве входного аргумента, то она может ее извлечь с помощью той же функции guidata: handles = guidata(hObject); handles = guidata(gcbo); Итак, "открывающая" функция — единственное место, которое принимает и обрабатывает входные аргументы командной строки. В этой же функции имеется возможность произвести динамическую перестройку интерфейсных элементов и их свойств перед тем, как они появятся на экране. По умолчанию "открывающая" функция выполняет всего две операции — добавляет к структуре handles поле output, запоминает в нем указатель hobject (строка 59), а затем сохраняет модифицированную структуру handles (строка 62). Вторая функция, которую условно можно назвать "закрывающей", срабатывает перед завершением работы приложения (аналог обработчика события OnCancei в ВСВ и Delphi). Ее вызов осуществляет система, передавая ей следующие входные и выходные аргументы: varargout = twobutton_OutputFcn(hObject, eventdata, handles) Основное назначение этой функции — возвратить значения выходных параметров, сформированные приложением, в командную строку. По умолчанию она возвращает через массив ячеек varangout содержимое поля handles.output, т.е. значение указателя на окно нашего приложения (строка 76). Однако приложение может сформировать и другие выходные данные, поместив их в какие-то поля структуры handles. П тогда пользователь должен расширить набор команд в теле "закрывающей" функции пересылками выходных результатов в ячейки массива varargout с учетом фактического количества запрошенных данных (nargout). Наконец, лва оставшихся фрагмента представляют собой заготовки для функций обработки события Callback, связанного с первой (строки 79—83) и второй (строки 86—90) кнопками. На самом деле здесь находятся только заголовки функций, которые GUIDE строит по стандарту, склеивая значение свойства Tag со словом Callback: pushbuttonl_Ca.l.lback (hObject, eventdata, handles) pushbutton2_Callba.ck (hObject, eventdata, handles) Список входных параметров нам уже знаком. Для содержательной реакции на щелчки по кнопкам остается добавить по паре строк в каждый из обработчиков: 84 set(hObject,'String','Нажата 1') 85 set (handles.pushbuttor.2, 'String', 'Кнопка 2') ;
Проектирование интерфейса 387 91 set(hObject,'String','Нажата 2') 92 set(handles.pushbutton!,'String*,'Кнопка l'J; И теперь наше приложение нормально фиксирует кнопку, по которой пользователь щелкнул в последний раз (рис. 8.56). -/ twobutton :1 $£ Кнопка! #* ^%#$С Нежата 2; - 1 f-m . Рис. 8.56. GUI-приложение с двумя кнопками Таким образом, разработка приложения с двумя кнопками, которая в динамическом режиме потребовала написания порядка 20 команд, в среде GUIDE обошлась нам всего в четыре строчки. Правда, пришлось потрудиться на стадии размещения интерфейсных элементов и при установке нужных значений в Property Editor (Редактор свойств). Конечно, объем т- файла в GUI-приложении существенно превышает размеры программы, созданной нами вручную. 8.3.8. Использование контейнеров В среде MATLAB 7 появились два новых компонента — контейнеры типа panel и Button Group. Используем их для построения в среде GUIDE приложения, воспроизводящего на экране график одной из трех функций — sin (л:), cos(jc) или ехр(х). Ранее аналогичная программа обсуждалась в разд. 81.3 После вызова конструктора интерфейса (GUIDE) попробуем подобрать размеры графического окна, подобные использованным в разд. 8.1.3. Это можно сделать двумя способами. Во-первых, можно зацепиться указателем мыши за черный квадратик, расположенный в правом нижнем углу, и изменить размер формы на глазок. Во-вторых, после выделения графического окна можно вызвать Property Editor (Редактор свойств) и в развернутом свойстве Position задать width=4 80, height-зео. Предварительно следует установить пикселы в качестве единиц измерения, ибо по умолчанию установлено Units-characters.
388 Глава 8 Перенесем на левую часть графического окна Panel, которая будет служить контейнером для осей. Панель улучшает внешний вид приложения. Кроме того, в надписи над панелью никаких проблем с русскими символами не возникает. С помощью Property Editor (Редактор свойств) для панели следует сформировать значение свойства Title (заголовок), можно поварьировать свойствами шрифта (Font), ВИДОМ И шириной бордюрной рамки (Border). Положим на панель поле графика (объект axesl). Так как на координатных осях при построении графика появится разметка, то поля снизу и слева следует сделать с небольшим запасом (рис. 8.57). ИГ sincosexp. fig Ble Edit View Layout lools belp НПП Dg£B *%Й. «г-ЦЦ ^^¾ P- [ 1^ Select И Push Button ■ Slider ® Radio Button 0 Check Box Ш Edit Text .?» Static Text ЕЭ Pop-up Menu HUstbox EsSToggle Button JfifAces Построение графика- т -Функция— г sirtM г cosM С expfx) Рис. 8.57. Вид проектируемого приложения в редакторе GUIDE Разместим в правой части рамку для переключателей — Button Group, в свойствах которой изменим заголовок. Кроме группировки радиокнопок рамка будет следить за их переключением во время работы приложения. Если мы щелкнем по невыделенному переключателю, то ранее выбранный должен будет автоматически изменить свое состояние (раньше мы это поведение программ и ров&ч и сами). Для разнообразия изменим и вид границы вокруг рамки (BorderType=beveledin). Для радиокнопок, помещенных в рамку, надо выдержать одинаковые размеры. Этого можно достичь клонированием компонентов или установкой у
Проектирование интерфейса 389 иих одинаковых свойств в массиве Position. Затем с помощью редактора Align Objects (Выравнивание объектов) выровнять их по вертикали и задать одинаковое смещение между объектами. Теперь можно проконтролировать внешний вид приложения в работе, хотя ни одной строчки кода мы сами еще не написали. Запустим приложение (команда Tools | Run (Сервис | Запуск)). Если наше приложение еще ни разу не запоминалось и сохраняет стандартное название untitled.fig, то система предложит его сохранить в текущем каталоге. При этом мы увидим поле редактора кода, в котором конструктор интерфейса сформировал изрядное количество строк. После запуска на экране появится графическое окно нашего приложения, и если его внешний вид (рис. 8.58) нас удовлетворяет, то пора приступать к программированию обработчиков событий. До этого вы можете убедиться в том, что кнопки переключаются нормально, хотя с изменением их состояния никаких действий еще не запрограммировано. */ sincosexp 1 0.8 0.6 0.4 0.2 • ■) 0.2 0.4 0.6 - - НПО 0.8 -. 1 " ; г sinM <~ cosft) С ехр(х) 1 Рис. 8.58. Вид полуфабриката приложения после его запуска Возвращаемся в среду GUIDE и попробуем написать обработчик события при выборе переключателя sin(x). Выделяем эту радиокнопку и выполняем команду View | View Callbacks | Callback (Вид | Отобразить Callback-функции | Callback) — рис. 8.59. Конструктор интерфейса формирует заготовку для обработки указанного события и переводит нас в окно редактора кода на позицию, которую пользователь должен заполнить (пример 8.24).
390 Глава 8 View Property Inspector Object Browser M-file Editor . .. Vlew Callbacks ► .Callback | CreateFcn DeleteFcn ButtonDownFcn KeyPressFcn Рис. 8.59. Переход в тело Callback-функции [ Пример 8.24. Функция radiobuttonljCailbacid . .,.^¾.,,.._■•■ Vy? f.^ • »*• % Executes on button press" in radiobuttonl. function radiobuttonl_Callback(hObject, even'tdata, handles) % hObject handle to radiobuttonl (see GCBO) % evencdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) %. Hint: get(hObject,'Value') returns toggle state of radiobuttonl Комментарий в первой строке свидетельствует о том, что функция выполняется при щелчке по радиокнопке radiobuttonl. Среди параметров, передаваемых функции, важны первый и третий. Первый является указателем на объект, инициировавший событие callback, т. е. на радиокнопку radiobuttonl. По свойству value этого объекта мы определим, выделена ли данная радиокнопка (vaiue=i) или нет. В первом случае необходимо построить граФик функции sin(jc), во втором — почистить поле графика. Однако^и перед построением графика, и перед очисткой его поля необходимо активизировать объект axesi. Если этого не сделать, го и в результате выполнения функции plot, и в результате работы функции cla будет автоматически создан новый объект, который сведет на. нет все наши дизайнерские труды. Новое поле графика расположится поверх нашей заготовки и наедет на рамку с кнопками. Поэтому наша добавка к обработчику события callback выглядит так, как в примере 8.25. j Пример 8.25. Добавляемый фрагмент кода ' [ 'Щ" ,е>,*'С^''^'] axes(handles.axes!) % активизация поля графика if(get(hObject,'Value')==1) % проверка состояния радиокнопки
Проектирование интерфейса 391 x=0:0.1:2*pi; y=sin (х) ; plot(х,у); else cla end % построение графика sin (>.) % очистка поля графика Обработчики событий от двух остальных радиокнопок строятся по идентичной схеме. Результаты запуска приложения (рис. 8.60) показывают, что левое поле с оцифровкой оси у следует немного расширить. -)■ sincosexp г _ — Построение графика - 0.5 П 0.5 1 / / / Ч \ \ \ \ \ \ . \ / ■ / ЯПЕЭ (-функция "■ sinfx) (~ cos(x) С ежрМ •> sincosexp „.. Построение графика- 500 №0 300 200 .100 О 0 . у ^ I I 1 / / ипн г Функция— г С sinfx) Г соеМ Р ехрМ Рис. В.60. Результаты работы приложения sincosexp
Глава 9 Стандартные диалоговые окна Расширению интерфейсных возможностей приложения способствуют многочисленные диалоговые окна, реализованные в системе MATLAB. Их перечень приведен в табл. -9.1. Таблица 9.1 Наименование Назначение диалогового окна dialog Создание и отображение диалогового окна общего назначения errordlg Создание и отображение диалогового окна с сообщением об ошибке helpdlg Создание и отображение диалогового окна помощи inputdlg Создание и отображение диалогового окна ввода listdlg Создание и отображение диалогового окна со списком для выбора msgbox Создание и отображение диалогового окна с сообщением pagedlg Отображение диалогового окна для настройки параметров страницы printdlg Отображение диалогового окна для настройки параметров печати questdlg Создание и отображение диалогового окна с запросом uigetf ile. Отображение диалогового окна для извлечения имени файла для чтения uiputf ile Отображение диалогового окна для извлечения имени файла для записи uisetcolor Отображение диалогового окна для установки цвета uisetf ont Отображение диалогового окна для установки параметров шрифта warndlg Создание и отображение диалогового окна с предупреждением
394 Глава 9 9.1. Диалоговое окно общего назначения (dialog) Функция dialog создает и отображает диалоговое окно общего назначения, которое отличается от стандартного окна типа figure отсутствием меню и панели инструментов, неизменяемыми размерами, свойством модальности и др. Формат вызова функции таков: h = dialog (' Свойство_1', Значекие_1, . . .) Функция создает специализированное графическое окно (фигуру), устанавливает свойства, рекомендуемые для диалогового окна, и возвращает указатель на созданный объект. Перечень рекомендуемых свойств и соответствующие значения по умолчанию приведены в табл. 9.2. Кроме них могут быть использованы любые лругие свойства, характерные для объектов типа figure. Таблица 9.2 Свойство Значение Пояснение BackingStore BuLiionDownFcn Colormap Color HandleVisibility IntegerHandle InvertHardcopy off if iserapty(allchild (gcbf)>, close(gcbf), end [] DefaultUicontrol BackgroundColor callback off off MenuBar NumborTitle PaperPosi tion Mode Resize Visible WindowStyle none off auto dff on modal ОС Windows не запоминает окно для восстановления при перекрытии Реакция на нажатие клавиши Рисунок отсутствует Цвет фона — серый Указатель — вещественное число Не инвертировать цвет при печати Меню отсутствует Заголовок отсутствует Размещение на листе при печати Запрещена возможность изменять размеры Видимое окно Модальный стиль
Стандартные диалоговые окна 395 9.2. Окно с сообщением об ошибке (error dig) Окно с сообщением об ошибке является частным случаем диалогового окна общего назначения. Оно создается и отображается в результате вызова функции errordlg, которой может быть передано до трех параметров: errordlg errordlg('сообщение') i errordlg('сообщение','заголовок') errordlg('сообщение','заголовок','on') h = errordlg(...) В первом случае создается и отображается диалоговое окно с характерным знаком (рис. 9.1). По умолчанию заголовком окна является текст Error Dialog, а В поле окна находится текст "This is the default error string". Пользоваться таким окном смысла не имеет, т. к. оно никакой содержательной информации не несет. Во втором случае текст сообщения об ошибке воспроизводится как заданная строка, однако заголовком окна является текст по умолчанию — Error Dialog. Наиболее употребительным является третий вариант, когда и текст сообщения об ошибке, и заголовок окна задаются пользователем. Например: >>errordlg('Деление на 0','Ошибка') Окно, появляющееся в результате выполнения этой команды, приведено на рис. 9.1. •> Ошибка f- 'Л Деление на 0 OK Н9ЕЗ Рис. 9.1. Окно с сообщением об ошибке Четвёртый вариант вызова функции errordlg имеет смысл, если окно с таким же заголовком выдавалось ранее и было свернуто пользователем. В этом случае текст сообщения об ошибке подменяется на новый, а само окно раскрывается, выходя на передний план. Если окна с указанным заголовком не существовало или предыдущее окно было закрыто пользователем, то создается новое окно.
396 Глава 9 Модальный стиль диалогового окна с сообщением об ошибке означает, что пользователь обязан щелкнуть либо на кнопке ОК (эквивалент — нажатие клавиши <Eiuer>), либо свернуть, либо закрыть окно (т. е. произвести одно из перечисленных обязательных действий для продолжения работы программы). Щелчок на кнопке ОК приводит к исчезновению окна. Размер окна подбирается системой автоматически таким образом, чтобы текст сообщения поместился в окне. Если в текст сообщения включены управляющие символы (перевод строки, возврат каретки), то в диалоговом окне появится многострочный текст. При любом варианте обращения функция errordig возвращает указатель на созданное окно, однако это значение обычно никому не нужно. 9.3. Окно со справочной информацией (heipdig) Диалоговое окно со справочной информацией создается и отображается в результате вызова функции heipdig, которой может быть передано до двух параметров: heipdig heipdig{'справка') heipdig('справка','заголовок') h = heipdig(...) Единственное отличие окна помощи or окна с сообщением об ошибке заключается в характерной картинке, сопровождающей текст. Если не задай текст справки или заголовок окна, то им присваиваются значения по умолчанию — "This is the default help string." И Help Dialog. В наиболее употребительном варианте вызова пользователь задает оба параметра; >> heipdig('По умолчанию eps=2.220446049250313e-016','Помощь') Результат выполнения такой команды приведен на рис. 9.2. •> Помощь ННЕЭ По умолчанию eps=2,2204<1604925031 ОК Рис. 9.2. Окно со справочной информацией
Стандартные диалоговые окна 397 9.4. Стандартное окно для ввода строк (inputdlg) Если в приложении не предусмотрены интерфейсные компоненты типа Edit Text, то наиболее удобным средством ввода текстовой информации во время выполнения программы являются стандартные диалоговые окна типа inputdlg. Они создаются и отображаются в результате обращения к функции inputdlg, которой может быть передано до пяти параметров: res = inputdlg({подсказка)) res = inputdlg((подсказка},'заголовок *) res = inputdlg!{подсказка},■заголовок',iineNo) res = inputdlg({подсказка},'заголовок',IineNo,def_res) res = inputdlg({подсказка},'заголовок',IineNo, def_res,'on') res = inputdlg({подсказка},'заголовок',IineNo,def_res,'off') Первый аргумент представляет собой массив ячеек, значения строк которых отображаются над полями ввода. Количество полей ввода, одновременно отображаемых в ди&чоговом окне, определяется количеством элементов в массиве подсказка. Например: » ху = inputdlg({'к of center','у of center'},'Задайте координаты центра') Выполнение этой команды приводит к появлению диалогового окна с двумя полями ввода (рис. 9.3). Возвращаемое функцией значение в этом случае также представлено массивом ячеек, содержащим две строки, присваиваемые соответственно переменным ху(1) и ху(2). Главной неприятностью для отечественных пользователей является то, что подсказка, появляющаяся над строкой ввода, должна набираться латинскими буквами. Задайте х of center координаты .-■ ea |10D у of center (120 OK Cancel Рис. 9.3. Диалоговое окно с двумя полями ввода Дополнительное неудобство диалогового окна ввода заключается в том, что текстовый курсор для набора вводимых строк не появляется автоматически
398 Глава 9 в одном из полей ввода, и пользователь должен лишний раз щелкнуть, прежде чем начать набор запрашиваемых данных. После завершения набора строки не имеет смысла нажимать клавишу <Enter>, т. к. она не переводит курсор в следующее поле ввода, а возврашает его в первую позицию текущего поля. В очередное поле курсор набора переводится вручную — щелчком мыши по области ввода или нажатием клавиши <Tab> (<Shift>+<Tab>). По завершению набора вводимых данных необходимо щелкнуть на кнопке ОК, и только тогда набранные строки будут возвращены функцией, а диалоговое окно исчезнет: х-у = 400' 420' Перевод в числовой формат программа должна сделать сама, используя, например, функцию str2num. Щелчок на кнопке Cancel (Отмена) или закрытие окна приводят к тому, что функция возвращает пустой массив ячеек. Параметр lineNo определяет количество строк, допустимых в каждом из полей ввода. Он может быть задан скалярным значением, и тогда указанное число относится ко всем полям ввода, присутствующим в диалоговом окне. Если этот параметр задан вектором-столбцом, то каждый его элемент определяет количество строк в соответствующем поле ввода. Параметр lineNo может быть задан и матрицей размерности тхг. Первый столбец этой матрицы определяет этажность полей ввода, а второй столбец — ширину каждого ноля ввода в символах. Если в поле ввода разрешено набрать более чем одну строку, то соответствующий результат будет представлен массивом ячеек, в котором значением каждого элемента является очередная строка из поля ввода. Параметр def_Ans определяет значение по умолчанию, которое воспринимается как результат ввода, если пользователь ничего не набирает в том или ином окне ввода. Если диалоговое окно содержит несколько полей ввода, то параметр defAns должен быть задан массивом ячеек соответствующей размерности. Последний параметр, принимающий одно из двух значений (on или off), определяет, может ли окно изменять свои размеры или нет. Значение on означает, что диалоговое окно может изменять свои размеры и не является модальным. Приведем пример 9.1.
Стандартные диалоговые окна 399 ;; Пример 9.1. Ввод данных с помощью диалогового окна *-- -'■ •?&■& ,.*; prompt = {'Dimension- of matrix:','Name of colormap:'}; title = 'Параметры для функции peaks'; lines = 1; def = {'20','hsv.'}; answer = inputdlg(prompt,title,lines,def); В этом примере создается диалоговое окно с двумя полями ввода, первое из которых предназначено для задания размерности области определения функции peaks (по умолчанию будет принято значение 'го'), а второе — для выбора названия палитры (по умолчанию будет принято значение 'hsv') 9.5. Окно выбора из списка (listdlg) Стандартное диалоговое окно listdlg по своему функциональному назначению мало чем отличается от интерфейсного элемента типа List box. Оно создается в результате обращения к функции listdlg, которой передается список строк iist_str (значение свойства Liststring) и набор харакгери- стик окна в виде пар "свойство — значение": [sel_str, ok] = listdlg('Liststring',list_str,... ' Свойсггбо_1 ', Значение_1, . .. 'Свойство_2',Значение_2,... 'Свойство_к',Значение_к) Последовательность задания пар "свойство — значение" может быть любой, и список строк не обязательно указывается первым. Список строк liststr обычно представлен массивом ячеек, каждым элементом которого может быть строка переменной длины. Рассмотрим пример 9.2. I Пример 9.2. Выбор файла - - , ., , " » d = dir; » str = {d.name}; » [ind,ok] = listdlg('Liststring',str,... 'FromptString','Выбор файла',... 'SelectionMode','single')
400 Глава 9 В приведенном примере список строк представлен именами файлов текущего каталога, и в результате выполнения указанных команд появляется окно, представленное на рис. 9.4. Задание значения свойства stringList в этом примере очень упростила команда dir, которая извлекает список полных спецификаций всех файлов текущего каталога (в приведенном примере текущим каталогом оказался рабочий каталог MATLAB — с:\МАТЬАВД№огк). Дополнительно заданные значения свойств определили подсказку над списком (свойство Promptstring) и режим выбора (свойство SelectionMode) единственной строки (значение — single). ННИ^Ш^^А^] Выбор файла ж GUI 3.fig GUI_3.m Un'itlecQ.m a.txt sbc.m aero.jpg array2vec.asv array2vec.m bultonqroup.asv buttcrijioupl.asv buttongroupt.m buttongroup2.m cbl.asv cbl.m cb2. asv Г.1Й 3P.V ! OK Cancel [ Рис. 9.4. Диалоговое окно для выбора единственного файла Для выбора нужной строки можно щелкну!ь по ней (цвет этой строки изменится), а затем нажать кнопку ОК или клавишу <Enler>. В упрощенном варианте достаточно выполнить двойной щелчок па выбираемой строке. В любом из перечисленных случаев функция возвратит два целочисленных значения. Первое из них, присваиваемое в нашем примере переменной ind, определяет индекс выделенной строки. Второе значение, присваиваемое переменной ok, может быть равно г, если пользователь сделал выбор, или о, если он от выбора отказался. Последнее происходит, если нажимается
Стандартные диалоговые окна 401 кнопка Cancel (Отмена) или принудительно закрывается окно. Отказ от выбора приводит к возврату пустого множества (ind=n). Результат выбора файла buttongroup.m в приведенном выше примере выдает на экран результаты, нуждающиеся в пояснении: ind ok 12 Строка с указанным именем действительно находится в двенадцатой позиции отображаемого списка. Первая и вторая строки в соответствии с правилами Windows заняты точкой (признаком наличия корневого каталога) и двумя точками (признаком наличия каталога предыдущего уровня). Конечно, числовой индекс — еще не само значение выбранной строки, но с его помощью нетрудно получить имя. выделенного файла: » str(12) ans = 'buttongroup.m' Выбор файла GUIJ.fig GUI 3.m Urititled2.m a.trt abc.m aerd.' array2vec. asv array2vec.m buttcngroup.asy мШшдПТцШШшМ! buttDngroupl.asv bultonqrougl.m итыЖ cbl.asv bl.m cb2.asv cb2.rn r_h3 asv Select all _J OK Cancel Рис. 9.5. Множественный выбор
402 Глава 9 Значение свойства seieetionMode по умолчанию равно multiple, что позволяет сделать множественный выбор. В этом случае в диалоговом окне появляется третья кнопка с надписью Select all, обеспечиваюшая выбор всех строк отображаемого списка (рис. 9.5). В случае множественного выбора первое возвращаемое значение представлено вектором, компоненты которого совпадают с индексами отмеченных строк (технология выделения нескольких строк подробно обсуждалась в гл. 8). Список свойств, значения которых так или иначе влияют на внешний вид и функционирование окна listdig, приведен в табл. 9.3. Таблица 9.3 Свойство ListSize Select i.onMcde InitialValue Name' PromptString OKString CancelString uh .fus Описание Ширина и высота списка в пикселах задается в векторе [width height] Режим выбора — единичный (single) или множественный (multiple) Вектор, определяющий начальное выделение Заголовок диалогового окна Массив строк или массив ячеек строк, который появляется над списком в качестве пояснительного текста Строка с надписью кнопки ОК Строка с надписью кнопки Cancel (Отмена) Высота кнопок в пикселах Зазор между рамкой и списком в Значение по умолчанию [160 300] multiple 1, что соответствует первой строке списка Пустая строка ]) — пустой массив ОК Cancel 18 В ffs пикселах (Frame/uicontrol spacing) Зазор между рамкой и границей окна в пикселах (Frame/figure spacing) 9.6. Диалоговое окно с сообщением (msgbox) Функция msgbox создает и отображает диалоговое окно, в котором текст сообщения может сопровождаться значком, характерным для окон типа
Стандартные диалоговые окна 403 errordlg, helpdig, warndig. По желанию пользователя в окне может быть отображена произвольная картинка. Существует несколько форматов обращения к функции msgbox: msgbox (сообщение) msgbox(сообщение,'заголовок') msgbox(сообщение,'заголовок', 'значок') msgbox(сообщение,'заголовок','cusrom',icon_data,icon_color_map) msgbox (...,' регеим') h = msgbox(...) Текст сообщения задается вектором-строкой, массивом строк равной длины или массивом ячеек со строками разной длины. При необходимости длинный текст автоматически разбивается на строки так, чтобы поместиться по ширине окна. Текст заголовка переносится в заголовок окна. В качестве параметра значок может выступать одна из строк: none', 'error', 'help', 'warn' или 'custom'. По умолчанию создается диалоговое окно без картинки, что эквивалентно заданию параметра "попе". Для создания окна с картинкой по выбору пользователя после параметра custom должны быть указаны данные (icondata — графический образ) и цвет (icon_map_coior). В качестве необязательного параметра режим может быть задана одна из строк: modal', 'non-modal' ИЛИ 'replace'. В первом случае окно будет модальным, во втором — немодальным, а в третьем оно заменит предшествующее окно с таким же заголовком. 9.7. Интерактивная настройка параметров страницы (pagedlg) Функция pagedlg предназначена для установки параметров страницы, на которой предполагается напечатать текущую или указанную фигуру- В системе MATLAB 7 она считается устаревшей, вместо нее предлагается более современная версия pagesetupdlg. Однако вы можете обратиться как к новой, так и к устаревшей функции. Последняя допускает вызов без параметров, если речь идет о текущем графическом окне, или с единственным аргументом — указателем на другое графическое окно. pagedlg(hFig) После вызова функции pagedlg появляется окно, представленное на рис. 9.6. Некоторые поля этого окна содержат неизменяемую информацию.
404 Глава 9 например, габариты листа бумаги, заправленной в принтер (Paper Size (Размер листа)). Указанный на рисунке формат слегка отличается от принятого у нас стандарта А4 (210x297 мм). Единицы измерения длины (Paper Units) можно сменить на более привычные. В зависимости от соотношения ширины к высоте можно выбрать либо портретную, либо альбомную ориентацию изображения на странице (Paper Orientation (Ориентация листа)). В правой области автоматически воспроизводится силуэт фигуры, которую предполагается отпечатать. -> Page Position: Figure 1 Paper Size: [2D.S84 29.677J Paper Units. jcentirTIBters J Paper Onentalion: | po[1ra|| J С Malch Paper Area to Figure Area f Set Paper Position Explicitly • Paper Position Default Paper Settings Center Help Print... г ■* BHQ ' llCL.63452 6.3452 20.305 15.228] Fill FillfFixed Aspect Ratio) Cancel Done Рис. 9.6. Окно настройки параметров страницы При печати фигуры имеется возможность произвести ее масштабирование под размер бумаги (Match Paper Area to Figure Area (Согласовать размеры листа и рисунка)) или потребовать точного соблюдения размеров выводимого изображения (Set Paper Position Explicitly (Установить положение рисунка па листе)). Поле Paper Position (Положение листа) позволяет задать прямоугольную область на странице, в которую должна быть вписана выводимая фигура. Кнопка Default Paper Settings (Установки листа по умолчанию) позволяет восстановить значения параметров страницы, заданные по умолчанию. С помощью кнопки Fill (Заполнить) можно растянуть выводимое изображение на всю страницу. При этом масштабирование по ширине и высоте производится с разными коэффициентами, что может привести к не очень удачным пропорциям (для преобразований такого рода используют
Стандартные диалоговые окна 405 термин анизотропное). В отличие от этого, кнопка FiII(Fixed Aspect Ratio) (Заполнить с сохранением масштаба) осуществляет изотропное преобразование, при котором производится изменение масштаба с сохранением исходных пропорций. Кнопка Center (По центру) перемещает выводимое изображение в центр листа бумаги. Кнопка Print (Печать) вызывает диалоговое окно печати, в котором можно выбрать принтер, установить его свойства, отпечатать заданное количество копий или направить образ выводимой страницы в файл. 9.8. Диалоговая страница (pagesetupdlg) Новое диалоговое окно для выбора параметров страницы встроено в главное меню File | Page Setup (Файл | Параметры страницы). При вызове функции pagesetupdlg появляется окно, приведенное на рис. 9.7. Достаточно подробно характеристики этого окна и всех его вкладок рассматривались в разд. 2.6.5. Page Setup - Figure 1 Q Size and Position | Paper ) Lines and Text ) Axes and Figure ) Mode С Use screen size, centered on pagel P Use manual size and position Manual size and position - Top: |ё~ш |J Left: |oJ5 g • Width: |го.зо |[" Use defaults FIN page Fix aspect ratio HeiBhl |йя Ц Unitsj centimeters -^] ' Center Help.. OK Cancel Рис. 9.7. Диалоговое окно pagedialogsetup
406 Глава 9 9.9. Окно настройки параметров печати (printdlg) Диалоговое окно, предназначенное для установки параметров печати, появляется в результате обращения к функции printdlg (рис. 9.8). Она допускает несколько форматов вызова: printdlg printdlg(hFig) printdlg('-crossplatfoim1, hFig) printdlg!'-setup',hFig) Печать - Принтер Имя. [Symantec Fax Starter Edition Состояние- Готов Тип: OLFAXDRV Место: OLFModem -г I Свойс Комментарий; Отправка факса выполняется путем печати р~ Печать в файл Диепазон печати <• Есе Г L'Tqjfc-V-ui &' С Виде,ic-iiHHp Фрй|'-itn; -Копии- Число копий: |1 ^fj OK j Отмена Рис. 9.8. Стандартное окно установки параметров печати (принтер на данном компьютере не установлен) Указатель hFig задается в том случае, если предполагаемые установки относятся к графическому окну, которое не является текущим. Параметр -crossplatform отображает диалоговое окно для подготовки печати на кросс-платформах Microsoft Windows и Macintosh. При его задании появляется окно, представленное на рис. 9.9. Основная особенность этого окна заключается в большом количестве доступных, драйверов прингеров, вывод на которые возможен либо с использованием сетевых устройств печати, либо путем подготовки файлов и переноса их на другие компьютеры. Раскрывающийся список Driver (Драйвер) включает более 30 позиций, полный пе-
Стандартные диалоговые окна 407 речень которых приведен в табл. 9.4. Не менее впечатляет список возможностей, открывающихся по кнопке Options (Опции) — рис. 9.10. Print: -Destination "■ printer; (~ File: Driver: i Figure 1 E3 OLFNufteni ■ Windows j»j г Figure Size on Printed Page ! f~ Same size as screen 1 С 20,3 by 15,2 cm Help.. ~— - ■- Brof'sc- Options... f Same as onscreen. 6 Allow MATUB to select OK Cancel 1 Рис. 9.9. Окно настроек для кроссплатформного вывода Таблица 9.4 № 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Драйвер принтера Windows Color Windows Postscript Postscript Color Postscript Level 2 Postscript Level 2 Color HPGL HP LaserJet HP LaserJet Plus HP LaserJet Ild/llp HP LaserJet III HP LaserJet 4/5L/5P HP LaserJet 5/6 HPDeskJet 500C 24 bitcolor HPDeskJet 500C b+w HPDeskJet / HPDeskJet Plus № 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 Драйвер принтера HP DeskJet 550C/560C/660C/660Cse HP DeskJet 500C/540C HP DeskJet 500C HP PaintJet HP PaintJet XL HP PaintJet XL (alternate) HP PaintJet XL 300 HP DesignJet 650C Cannon BubbleJet 10c Cannon BubbleJet 200 Cannon BubbleJet 600/4000/700 Cannon BubbleJet 800 Epson Epson LQ-2550 Epson 9-pin IBM Proprinter I4 3ok 899
408 Глава 9 Printing Options Select optional Input arguments for PRINT command. See on-Iine.help of PRINT command for mora Information. Q Г |Jse loose bounding box for PB and Ghostscrlpt drivers! - Г Use CMYK colors In PS and Ghostscrlpt drivers Instead of RGB Г Use Adobe PS default character set encoding I~ Suppress printing of user Interface controls Handle Graphics Renderer — <♦ Have MATLAB select based on complexity of graph <~ Render using painter's algorithm С Render using Z-buffer <~ Render using OpenGL Printing Resolution - & Have MATLAB select based on renderer and driver <"* Use same resolullon as the screen <~ Specify resolution In dols per inch: I OK Cancel 9.10. Окно дополнительных настроек режима печати Обращение printdig {' -setup', fig) вынуждает диалоговое окно появиться в режиме установки. 9.10. Диалоговое окно с запросом (questdlg) Диалоговое окно, содержащее запрос, создается и отображается с помощью функции questdlg, которой передаются от одного до шести параметров: btn = questdlg('запрос') btn = questdlg('запрос','заголовок') btn = questdlg('запрос','заголовок','default') btn = questdlg('запрос','заголовок','btnl','btn2','default') btn = questdlg('запрос','заголовок','btnl','btn2','btn3','default') Первый аргумент представлен строкой, содержащей текст запроса. Второй аргумент, если он задан, воспринимается как заголовок окна.
Стандартные диалоговые окна 409 По умолчанию окно является модальным и содержит три кнопки: Yes (Да), No (Нет), и Cancel (Отмена). Граница кнопки Yes (Да) выглядит немного жирнее, и щелчок на ней эквивалентен нажатию клавиши <Enter>. В третьем варианте обращения параметр default может быть одной из строк вида 'yes', W или 'cancel'. Его значение определяет кнопку, которой ставится в соответствие нажатие клавиши <Enter>. Четвертый и пятый варианты предоставляют пользователю возможность задавать на двух или трех кнопках надписи по своему усмотрению. В этих случаях строки 'btnl', 'btn2' и 'btn3' задают нестандартные надписи. Параметр default, если он задан, должен совпадать с одной этих строк. Его значение определяет, какой из кнопок соответствует нажатие клавиши <Enter>. Если пользователь закроет окно, не нажав ни одной кнопки, то значением функции является пустая строка. В любом случае функция questdig возвращает строку с надписью нажатой кнопки. Анализируя значение переменной btn, программа может узнать, как ответил пользователь на выставленный запрос. » a = questdig('Продолжить ?','Ваш выбор'); » if a=='Yes'... В результате вызова функции questdig на экране появляется окно (рис. 9.11). Ваш выбор \У J Продолжить . 1 Yes | No | ? Cancel □ 1 Рис. 9.11. Интерактивный запрос 9.11. Выбор имени файла для чтения (uigetfile) Диалоговое окно, обеспечивающее возможность выбора имени файла из текущего каталога (рис. 9.12), появляется в результате вызова функции uigetfile: [file_name,file_path]=uigetfile('*.m','Выберите файл')
410 Глава 9 Выберите файл НО Папке: |'—' work £j.abc Earray2vec fibuttongroup Bbuttongroupl £]buttongroup2 Qcbl Ecb2 «I Ucb3 Srb4 Scheckl fDedit textl fifed ■Ejfern "EjGUI 3 d- yiistl ■Elist2 ■Elpstal ■Ejpolyline fipopup_menu "tDpcipup_menul fipcpup menu2 I Ec* m- fipr8_26 Qpushbtn fipushbtni Cjpuahbtri5 Sradiol firoots2 &oots3 e £ 4 Имя файла | Тип файлов: |M-filesC".m) Открыть "3 Отмена Рис. 9.12. Интерактивный выбор файла дли чтения Первый аргумент играет роль фильтра, ограничивающего список имен файлов, отображаемых в диалоговом окне. Второй аргумент воспринимается как заголовок окна. Выбор файла может быть сделан либо щелчком по имени, либо путем набора имени файла с клавиатуры. После выбора имени файла пользователь может нажать кнопку Открыть (Done), отказаться от выбора щелчком по кнопке Отмена (Cancel) или путем закрытия окна. Если файл выбран и нажата кнопка Открыть (Done), то функция возвращает две строки с именем файла и полным путем к файлу. В приведенном выше примере строка с вызовом функции не завершается точкой с запятой, поэтому после выбора файла возвращаемые значения выводятся в командное окно: file_name = Animl.m £ile_path = C:\MZYTLAB7\work\ Если пользователь отказывается or выбора, то функция возвращает два нуля: file_name = б file_path = О Набор имени несуществующего файла приводит к появлению окна с сообщением об ошибке (рис. 9.13). После нажатия кнопки ОК вы можете набрать имя другого файла или отказаться от выбора.
Стандартные диалоговые окна 411 Выберите файл целка: | LJ work ВЕЗ ~^~1 <- Eg с* ШЬ- fiabc Qarray2vec Bbuttongroup fibjttongroupl fibuttongroup2 tlcbl ficb2 4 | ficb3 ■ВсЫ ficheckl Oedit textl Qfed fifern €lGUI_3 -fcjlisti fillst2 fipetal fipolyllne fipopup menu fipopup menul fipopup menu2 1 *jpr8 26 fipushbtn fipushbtnl fipushbtn5 firadiol ■&oots2 firaots3 Я fi fi fi fi « fi ►J Имя файла' Выберите файл ЕЗ .Тип файлов: M-files Cm; j\ ebcd Этот файл не найден. Проверьте правильность имени файла. ОК Рис. 9.13. Реакция на ошибку в наборе имени файла MATLAB предусматривает возможность позиционирования окна по выбору файла: uigetfile('*. *','ВыБор файла',20,20) Однако Windows на задание координат не реагирует и располагает окно по своему усмотрению. Выберите файл ВЕЗ Полно: |_)work Ыа fiabc йаегб Ш array 2vec Barray2vec Sbuttonqroup Ebuttongrsup 4 | Mbuttongroupl flbuttongroup 1 fibuttondroup2 Scbl flcbl &ЭсЬ2 •Qch2 1 ЫсЬЗ тЗсЬЗ йсЬ4 ficheckl M data 1 Sdata2 Sdata3 z] *• ED ИМИ-- 4 dim fiedit textl fifed afern fifern fiGUI 3 fiGUl 3 ti fi ф ti из fi g .►J Имя файла: Г 1ип файлов: | • I Files .*) Открыть ~Б Отмена Рис. 9.14. Фильтр отбора * . *■
412 Глава 9 На наш взгляд, в реализации диалогового окна uigetfile авторы MATLAB напрасно опустили вывод расширений файла. Дело в том, что в каталоге могут присутствовать файлы с одним и тем же именем, имеющие разные расширения. Пример тому— задание фильтра отбора *.*. Результат представлен на рис. 9.14. И сделать выбор файла в такой ситуации не так-то и просто — надо ориентироваться не только на название файла, но и на сопровождающий его значок. Название кнопки Открыть не совсем точно передает англоязычный эквивалент Done (дословно — выполнить). Может создаться впечатление, что выбранный файл открыт. На самом деле программа только узнала имя файла, которое еще предстоит открыть с помощью функции fopen. 9.12. Выбор имени файла для записи (uiputfile) Выбор файла для записи с помощью функции uiputfile несколько отличается от выбора имени файла, содержащего входные данные. Если файл с входными данными должен обязательно существовать, то в качестве файла с выходными данными можно использовать как существующий, так и несуществующий файл. В первом случае система должна запросить подтверждение на уничтожение имеющихся данных, чтобы пользователь по ошибке не удалил полезный файл. Для вызова функции uiputfile разумно использовать один из двух следующих форматов: [fiie_name,file_path]=uiputfile('*.m','Заголовок') [file_name,file_path]-uiputfile!'fname','Заголовок') Первый вариант, более распространенный, позволяет увидеть, какие файлы с заданным расширением уже присутствуют в текущем каталоге. Здесь имеется возможность набрать новое имя или выбрать уже существующий файл. Во втором случае первый аргумент сразу задает имя файла для выходных данных, которое появится в поле ввода диалогового окна. Конечно, от этого имени можно отказаться, набрав или выбрав другое имя. Если выбираемый пользователем файл существует, то появляется дополнительное окно с целью предупреждения опрометчивого действия (рис. 9.15). Вектор значений, возвращаемых функцией uiputdlg, таков же, как и при выборе файла ввода — имя файла и путь к файлу. В случае отказа от выбора функция возвращает нулевые значения.
Стандартные диалоговые окна 413 Выберите файл для вывода Попка: | О work ИВ ■^1«- э гЗ ешн Babe fiarray2vec Hbuttongroup fibuttongroupl Bbuttongroup2 Qcbi Dcb2 <l ' ficb3 ficW Qcheckl •Eledit textl fifed fifem fiGUI 3 ■V7j •fcJlistl &pr8 26 Ciist2 ■BpusJibm fipetal fipushbtnl fipolyllne ■Bpushbtn5 fipopup menu firadlol ■Bpopup menui £lroots2 fipopup_menu2 firoobs3 "' ; 1 -:b ~ ti Q У fi fi ti « >i Имя файла: p 1ип файла: |M-filas(*.m) f\ ■Select File To Write E H:\fy1AJLASAwo(;k\abc.m already exists," Do you want to replaee.lt? Да Вет Рис. 9.15. Запрос на замену существующего файла 9.13. Диалоговое окно для выбора цвета (uisetcolor) Диалоговое окно по выбору цвета предлагает две возможности. Во-первых, по красочной мозаике, представленной в основном окне, можно получить тройку RGB-компонентов, соответствующую выбранному цвету. Делается это следующим образом: » с = uisetcolor([1 0 0],'Выбор цвета') В результате выполнения этой команды появляется диалоговое окно (рис. 9.16) с красочной мозаикой, в которой пунктирным прямоугольником выделен элемент, цвет которого совпадает с RGB-вектором, заданным в первом аргументе (вектор цвета [1 о 0] соответствует красному цвету). Обратите внимание на первый элемент во втором ряду. После появления окна с палитрой из 48 цветов пользователь может щелкнуть по любой клеточке и нажать кнопку ОК. Тройка чисел, соответствующая выбранному цвету, возвращается в качестве результата и засылается в переменную с. Если палитра основных цветов покажется пользователю слишком бедной, то можно нажать кнопку Определить цвет » (Define color »). Тогда окно по выбору цвета пополнится новыми средствами формирования цветовых оттенков (рис. 9.17). Понравившиеся пользователю цвета могут быть перенесены в таблицу дополнительных цветов.
414 Глава 9 Выбор цвета Основные цвета Г5П ПИ ВЕЗ 'EB-I Дополнительные цвета: гггггггг гггггггг Определить цввт » ок Отмене Рис. 9.16. Окно выбора цвета Выбор цвета Основные цвета- г"г~г~г~г"(агтгт ~l—I—I—ЕГГТ 5Г"=.- ИГИГ Дополнительные цвета: ГГГГГГГГ г- ВЕЗ "B»'.fe ип1ял|чч"ьце- | » ок Отмена Щ~'С ! Оттенок:(() Красный: |255 раод К,онтраст:рЧС1 Зеленый: |0 Цвет|Звпивко Яркйсть:|120 Синий: [5 Добавить в набор Рис. 9.17. Расширенная палитра для выбора цветовых оттенков Второй вариант использования цветового окна связан с выбором окраски объекта, чей указатель задается в качестве первого аргумента функции uisetcolor: » hBtn = uicontrol('Style','pushbutton','String', 'Кнопка');... uisetcolor(hBtn,'Задайте цвет кнопки');
Стандартные диалоговые окна 415 Кнопка типа pushbutton обладает свойством color, задающим цвет символов надписи. Поэтому после выбора цветового элемента и нажатия кнопки ОК надпись Кнопка (Button) окрасится в выбранный цвет. 9.14. Диалог по выбору параметров шрифта (uisetfont) Шрифт Обладает РЯДОМ СВОЙСТВ — FontName (ИМЯ Шрифта), FontUnits (единицы измерения), Fontsize (размер символов), Fontweight (толщина линий контура), FontAngie (угол наклона символов). Эти же свойства присущи различным графическим и интерфейсным объектам. Диалоговое окно по выбору параметров шрифта позволяет визуально оценить качество назначаемых вами значений. В простейшем случае отображение этого окна происходит при вызове функции uisetfont без параметров: » ш setfont Окно, появляющееся при выполнении этой команды, приведено на рис. 9.18. Шрифт Шрифт: Начертание Ariel >Г ©SimSun '*Г Academy Engraved LET- 'jt' Amaze I p Arial Black IО Arial Narrow. I 7r Arial Unicode MS Еезмер: |!Я?ИИ!ЯЗ zJ курсив жирный жирный курсив Образец™—- 1« -Z. АаВЬБбФф На£ор символов; [Кириллический "3 12 8 л 9 — 10 ОК Отмене Рис. 9.18. Окно выбора параметров шрифта После установки нужных значений и щелчка по кнопке ОК функция возвращает структуру следующего вида: ans = FontName: 'Arial'
416 Глава 9 FontUnits: 'points' FontSize: 12 FontWeight: 'normal' FontAngle: 'normal' Сформированная структура может быть присвоена любой переменной, например s, или приписана любому графическому или интерфейсному объекту, если его указатель hobj приведен в качестве параметра функции: » S = uisetfont; » uisetfont(hObj); Если вы объявили структуру s с указанными выше полями и присвоили им соответствующие значения, то эта структура может быть задана в качестве первого аргумента функции uisetfont. При этом в диалоговом окне все параметры шрифта будут установлены по значениям соответствующих полей структуры. Вторым аргументом функции uisetfont является строка, играющая роль заголовка диалогового окна по выбору шрифта: uisetfont(h,'заголовок') uisetfont(S,'заголовок'> Заголовок окна может быть и первым аргументом, если среди параметров функции отсутствуют указатель на.объект или структура с начальными установками: uisetfont('заголовок') Если пользователь отказывается от выбора параметров шрифта и нажимает кнопку Отмена (Cancel) или закрывает окно, то значения всех возвращаемых свойств равны о. 9.15. Диалоговое окно с предупреждением (warndlg) Для формирования и отображения диалогового окна с предупреждением используется функция warndlg, которой передаются до двух аргументов: warndlg warndlg('предупреждение') warndlg ('предупреждение', ' заголовок,') h=warndlg(...)
Стандартные диалоговые окна 417 Без параметров эта функция не употребляется, т. к. отображает диалоговое окно с заголовком Warning Dialog и строкой предупреждения "This is the default warning string". Пользы от такого окна, конечно, нет. Более содержательное обращение: » warndlgfBbi забыли изменить eps',' Предупреждение') вызывает появление диалогового окна, приведенного на рис. 9.19. -> Предупреждение ВВЕЗ Вы забыли изменить eps OK I Рис. 9.19. Окно предупреждения 9.16. Полоса прогресса С помощью командной строки » hWB=waitbar(0,'Wait please...');for i=l:10000,waitbar(i/10000,hWB), end создается окно с полосой прогресса (рис. 9.20). Рис. 9.20. Бегущая полоса Из приведенного примера следует, что первое обращение к функции waitbar с нулевым аргументом создает окно, в котором полоса ожидания прижата к начальной позиции и практически не видна. Функция возвращает указатель hWB на созданный компонент, который используется в последующих обращениях. При повторных обращениях к функции waitbar с постепенно увеличивающимся значением первого аргумента бегущая полоска продвигается к правой границе, достигая ее, когда первый аргумент
418 Глава 9 становится равным 1. Так, например, можно отображать процесс копирования длинного файла, вычисляя долю уже переписанных байтов относительно длины файла. При повторных вызовах функции waitbar можно задавать дополнительный аргумент в виде символьной строки, который заменит застывшее Wait please..., например, на процент от объема выполненной работы. В программе из примера 9.3 внутренний никл по j имитирует некоторый процесс. В зависимости от скорости вашего компьютера количество повторений внутреннего цикла, возможно, придется уменьшить. На рис. 9.21 показан промежуточный вид полосы прогресса. • ■ v "г^"^т"5Ч".и:"""'?" .■ •"-ргжщтр^щгхщ жщг'~*щ ■ ; Пример 9.3. Отображение полосы ожидания ■ '.-п.- ^ .;. ■*•,.'._ h=waitbar(0); % создание начального объекта tor i=l:100 s=int2str(i); s=strcat(s,'%'); for j=l:10000000 end waitbar(i/100,h,s) % модификация шкалы прогресса end Рис. 9.21. Индикация выполняемого процесса Из любопытства после формирования окна индикации (h=waitbar;) можно обратиться к функции get(h) п проанализировать свойства этого необычного объекта. Самое интересное, что свойство style имеет значение figure, (т. е. графическое окно специального типа). Во-вторых, свойству Tag, которому функции uicontrol не присваивали никакого значения, здесь присвоена строка 'TMFWaitbar'. По умолчанию функция waitbar (0) формирует окно с полосой, над которой находится текст 'waitbar'. Отметим еше одну особенность этого объекта — он может существовать только в единственном экземпляре. Попытка создать еще одно окно такого же типа не удается (пример 9.4).
Стандартные диалоговые окна 419 j Пример 9.4. Попытка создания двух полос одновременно » hl=waitbar(0) hi = 3.0043 » h2=waitbar(0) h2 = 3.0043 Оба указателя имеют одно и то же значение, т. о. в обоих случаях речь идет об одном и том же объекте. г
Глава 10 Визуализация трехмерных объектов Технология визуализации трехмерных объектов использует довольно много специ&чьных терминов, характерных для большинства систем машинной графики. С наиболее важными из них, влияющими на свойства отображаемых фигур, мы познакомимся в начале этой главы. Появлению изображения на экране предшествует довольно много процедур, связанных с вычислением цветности каждого пиксела изображения — учет положения и специфики источников света, определение видимых участков объекта и учет влияния их физических характеристик (отражение, преломление, диффузия). Все это вместе взятое составляет суть рендеринга — процесса визуализации компьютерной модели на экране. 10.1. Некоторые задачи и алгоритмы трехмерной визуализации 10.1.1. Аффинные преобразования и однородные координаты Одну из составных процедур рендеринга представляют различные линейные преобразования координат характерных точек отображаемого объекта, обычно вершин граней, — сдвиги, повороты, растяжения/сжатия, параллельное или центральное проектирование на ту или иную плоскость. Перечисленные преобразования образуют группу аффинных преобразований и в общем виде описываются следующими линейными уравнениями: Хноб = a-n*xCT + ai?*yCT + ai3*Zcr +bi", Уноа = a2i*xCT + а22*Уст + a2j*zCT +bz; zHcb = а31*Хст + аз2*Уст + a33*zCT +bj. Для того чтобы записать указанные равенства в матричной форме phdd=a*pc,. , используют следующий прием.
422 Глава 10 XHt!li У HOD ZH(U- 1 "а11 a21 a31 0 ai2 a22 a22 0 ai3 aZ3 взз 0 h," b2 b3 1 * Ч.Т Ус* ZCT 1 Расширим вектор координат, добавив к его трем естественным координатам четвертую, всегда равную 1: [ х; у; z ] -» [ х; у; z; 1 ]. Тогда описанное в формате (10.1) аффинное преобразование приобретает следующий вид: (10.2) Четверка расширенных таким образом координат известна под названием однородных координат. На плоскости однородные координаты точки представлены тройкой [х; у; ]]. Может показаться, что введение однородных координат увеличивает объем исходных данных. Но это не так — на самом деле искусственно добавляемую единицу можно хранить не в оперативной памяти, а "в уме", используя ее только в момент выполнения преобразований. Тогда в чем же преимущество формы (10.2) по сравнению с формой (10.1)'.' Во-первых, для каждого ■элементарного аффинного преобразования можно довольно просто сформировать соответствующую матрицу. Например, при сдвиге объекта на заданные смещения по каждой из координат (хнаР=хс..т+с1х, Унзб=у-,т+с1у, zHUE=zCT+dz) эта матрица имеет вид: "1 0 0 dx~ О 1 0 ау О 0 1 dz 0 0 11 Для сжатия/растяжения по каждой координате (хНоз=хСт*кх, у,!0в=уст*к..-, z.uoB=zCTkk.z) используется матрица: ку б О О' 0 ку О О О 0 к, О 0 0 0 1 Познакомиться с матрицами, описывающими различные аффинные преобразования, можно, например, в книге В. Н. Порсва "Компьютерная графика"1. Порев В. Н. Компьютерная графика. — СПб.: БХВ-Печербург, 2002.
Визуализация трехмерных объектов 423 Второй аргумент в пользу однородных координат и формата (10.2) аффинных преобразований появляется, как только над объектом нужно выполнить цепочку из двух или более преобразований с матрицами Аь Аг, ..., аГ1. Вместо того чтобы производить пересчет координат на каждом шаге, можно вычислить матрицу итогового аффинного преобразования и только один раз пересчитать все координаты: A=Ar.*An-i* . . . *Ai_ Р»в=АгЛ (An-i* . . . (Ai*PCT> = А*РСТ Умножение матриц 4-го порядка требует гораздо меньше операций, чем многократный пересчет всех вершин отображаемого многогранника. Именно это преимущество в объеме вычислений оправдывает использование однородных координат в любой системе машинной графики. Немаловажным аргументом в пользу этой технологии является и стереотипность выполнения аффинных преобразований — использование типовых шаблонов для формирования матриц каждого элементарного преобразования, умножение матриц 4-го порядка. 10.1.2. Растеризация векторных изображений Такие устройства отображения, как дисплеи и принтеры, обычно используют растровую технологию воспроизведения графических объектов. При этом изображение состоит из большого количества отдельных цветных точек — пикселов. Однако информацию об отображаемом объекте гораздо выгоднее хранить в векторном формате — коэффициентов соответствующих аналитических уравнений, координат концов отрезков, координат вершин многоугольников и т. п. Во-первых, так экономится объем оперативной памяти. Во-вторых, такие операции, как масштабирование и повороты фигур, в векторном формате осуществляются без потери качества. Поэтому одна из первых задач в системах отображения — растеризация — связана с преобразованием векторных данных в растровый формат. Она использует довольно простой математический аппарат, но ее лобовое решение приводит к большому объему вычислений, в которых значительная доля операций приходится на умножение (деление) вещественных чисел. Одним из первых исследователей, предложивших эффективный алгоритм вычисления координат точек растрового отрезка, проходящего через две заданные точки, с использованием только целочисленных операций сравнения и сложения (вычитания) был Брезенхейм (Bresenham J. Е., 1965 г.). Позднее (1977 г.) он же распространил подобную схему на вычисление растровых координат точек на дуге окружности. Существенно позже аналогичная схема была предложена и для растеризации дуг эллипсов. Перечисленные алгоритмы оказались настолько удачными, что их имплантируют в аппаратуру современных графических ускорителей.
424 Глава 10 10.1.3. Воспроизведение утолщенных линий Задача воспроизведения утолщенных линий на растровой сетке не такая уж и тривиальная, как может показаться. Лобовое ее решение путем построения семейства симметричных эквидистант относительно осевой линии приводит к появлению семейства мелких точек, сквозь которые просвечивают фоновые пикселы. На вид толстых линий оказывает ачияние и форма пишущего узла (апертура пера), из-за которой на стыках прямоугольных отрезков могут наблюдаться различного рода зазубрины — выступы, впадины. Чтобы построить качественную прямоугольную рамку с толщиной линии w, приходится строить отрезки, концы которых выступают на w/z относительно координат осевой линии. Многие графические системы, включая и Windows GDI, предоставляют пользователю возможность задать такие характеристики пера, как стиль сочленения смежных отрезков (joint style) и тип окончания отрезка (end cap) — закругленный, перпендикулярный осевой, параллельный одной из осей координат в зависимости от наклона отрезка. 10.1.4. Устранение невидимых частей изображения Существует довольно много разных по сложности и быстродействию алгоритмов удаления невидимых точек, линий и поверхностей. Среди них можно указать методы прямой (от источника освещения) и обратной (от позиции наблюдателя) трассировки лучей (ray tracing), излучательности (radiosity), сортировки по глубине, Z-буфера и др. Наиболее простая идея, которая нашла свое воплощение и в аппаратуре, заножена в алгоритмах Z-буфера. Название этих методов с выбором направления оси z, которая из картинной плоскости (т. е. плоскости экрана) направлена на наблюдателя. Считается, что его позиция достаточно удалена от экрана, так что лучи, направленные от картинной плоскости в сторону наблюдателя, можно рассматривать как пучок прямых, параллельных оси z. Для каждой точки объекта, расположенного перед картинной плоскостью, ее г-координата совпадает с расстоянием от этой точки до плоскости экрана. Поэтому, если на одном и том же луче находятся две или более точки объекта, то видимой окажется та, которая расположена ближе к наблюдателю, т. е. та, которая имеет большую г-координату. Поэтому сравнение z- координат пикселов, проектируемых в одну и ту же точку на картинной плоскости, решает проблему видимости изображения. На практике простейший алгоритм г-буфера реализуется с помощью двух буферов одинакового размера. Один из них предназначен для хранения двумерной матрицы цветностей пикселов картинной плоскости. При использо-
Визуализация трехмерных объектов 425 вании 24-битовой кодировки RGB-компонентов и разрешении экрана 1024x768 для такой матрицы потребуется порядка 4 Мбайт. Второй буфер служит для хранения 32-разрядных целочисленных значений г-координат точек отображаемого объекта. В начальный момент буфер цветности заполняется кодом фонового цвета, а буфер г-координат — нулями. При анализе очередного пиксела изображения его г-координата сравнивается с соответствующим расстоянием ранее обработанного пиксела, уже записанного в Z- буфер. Если новое расстояние больше, то код цветности пиксела заносится в соответствующую позицию буфера цветности, а аппликата подменяет предыдущее Z-значение. В противном случае обрабатываемая точка считается невидимой. * 10.1.5. Окрашивание граней полигональных моделей В волновой теории света считается, что свет представляет собой поток фотонов, испускаемых источником и несущих электромагнитные колебания разной частоты. Для человеческого глаза видимый поток света принадлежит диапазону от 380 нм (нижняя граница фиолетового излучения) до 780 нм (верхняя граница красного излучения). Под интенсивностью I падающего луча понимают отношение энергии светового потока к площади освещаемой им поверхности. Часть падающих лучей отражается от поверхности, часть поглощается ею, часть проходит через поверхность и преломляется. Благодаря отраженным лучам мы видим освещаемые предметы. Отражение световых лучей представляет собой довольно сложный процесс, на одной из границ которого находится абсолютное зеркальное отражение (specular reflection), а на другой — полное диффузное рассеяние (diffuse reflection). Зеркальное отражение имеет место при падении светового луча на идеально гладкую поверхность (помните из школьной физики — "угол падения равен углу отражения"?). К очень гладким поверхностям мы относим такие, у которых шероховатость, образуемая впадинками и выпуклостями, имеет размеры меньшие, чем длина световой волны. Для таких поверхностей угол отражения можно считать равным углу падения, а интенсивность отраженного луча iOTp прямо пропорциональной интенсивности падающего луча i: При встрече луча со слабо шероховатой поверхностью имеет место отклонение отраженного луча от идеального направления на угол ее. В этом случае зависимость интенсивности iQ4J от интенсивности падающего луча i существенно нелинейна и должна учитывать степень шероховатости освешаемой поверхности. В системах машинной графики с целью уменьшения объема
426 Глава 10 вычислений используют более простые эмпирические формулы. Одной из них является формула Фонга (Phong): 10тр = ks * I * cospcc. Показатель степени p (Фонг называл его коэффициентом резкости бликов (shininess coefficient)) подбирается эмпирическим путем. Для идеального зеркала р = 8, для металлических поверхностей коэффициент резкости бликов находится в интервале от юо до 500, для обычных материалов его значение не превышает юо. При очень большой шероховатости (такие поверхности называют матовыми) отражение лучей осуществляется равномерно во все стороны — происходит так называемое диффузное рассеяние. Если обозначить через <р угол падения луча (угол между направлением светового потока и вектором нормали к освещаемой поверхности), то интенсивность отраженного луча, достигающего позиции наблюдателя, в случае диффузного рассеяния подчиняется закону Ламберта: 1циф = I * kd * coscp. В интенсивность наблюдаемого излучения, кроме перечисленных выше двух составляющих i0.rp и iBl,4„ вносит свой вклад и фоновая подсветка (ambient light), создаваемая рассеянным светом, отраженным от других предметов, — 1фон- В описанных выше физических явлениях и приведенных формулах явно или неявно присутствует вектор нормали к освещаемой поверхности, построенный в точке падения луча. В машинной графике поверхности трехмерных тел заменяются полигональными моделями, сформированными, как правило, из треугольных или четырехугольных граней (Patches). Так как каждая из таких граней принадлежит плоскости, описываемой уравнением Ах + By + + cz = о с известными коэффициентами, то построение вектора нормали для внутренних точек грани и определение косинуса угла между парами векторов (нормаль, вектор падающего луча) или (нормаль, вектор в позицию наблюдателя) выполняется по довольно простым вычислительным схемам. Они достаточно хорошо согласуются с операциями над векторами, реализованными в MATLAB (см. гл. 12). Самый примитивный алгоритм однотонного окрашивания граней, известный под названием flat, базируется на предположении, что все точки ipa- ни освещены одинаково. Это более или менее допустимо при бесконечно удаленном источнике света, когда лучи в световом потоке параллельны, а размеры граней достаточно малы. Обычно выбирается некоторая характерная точка на грани, например, аналог центра масс вершин, в ней вычисляется освещенность, приписываемая всем остальным точкам. Так как при переходе на соседнюю грань освещенность терпит разрыв, то на отображаемом объекте четко прорисовываются ребра и отчетливо видна фасеточная структура поверхности.
Визуализация трехмерных объектов 427 Для создания более реалистичного изображения полигональной поверхности Гуро (Н. Gouraud — сотрудник компании Autodesk, один из разработчиков 3D Studio) предложил алгоритм неравномерной закраски граней, основанный на применении билинейной интерполяции освещенности. В его схеме по сложным или упрошенным эмпирическим формулам вычисляют освещенность каждой вершины. Затем на отрезках, соединяющих две смежные вершины, для полсчета освещенности каждой точки ребра используют линейную интерполяцию. Обозначим через г* освещенность вершины с координатами (х1:, у1:, z1:), а через i^i освещенность соседней вершины с координатами (к):.ц, yktl, zk*j)- Тогда параметрические уравнения ребра, соединяющего эти вершины, имеют вид: х = хк +■ (хк+1 - хк) * t; у = у* + (у-,;+1 - х1:> * t; О < t < 1. z = zt. + (zk+i - jk) * t. Для внутренней точки м ребра, определяемой параметром tm, интенсивность освещенности вычисляется по формуле: 1н= Ik+ dk+i - Ik) * U, ■ Аналогичный расчет производится и для всех точек смежного ребра этой же грани. Затем пара точек смежных ребер с одинаковым значением параметра t соединяется внутренней хордой и на каждой точке хорды повторно производится линейная интерполяция освещенности. Если по алгоритму Гуро произвести расчет интенсивности отраженных лучей на смежной грани, то на стыке граней в точках общего ребра освещенность сохраняет свою непрерывность, однако ее первая производная терпит разрыв. Для избежания этого разрыва и создания более плавных цветовых переходов Фонг предложил интерполировать нормали к поверхности. Теперь они уже не образуют строго параллельные пучки на каждой грани, а рассыпаются в стороны наподобие иголок ежа, образуя плавный переход через ребра и вершины. Этот алгоритм связан с большими вычислительными затратами, но изображение поверхности при этом становится более реалистичным. 10.2. Создание и отображение криволинейных поверхностей 10.2.1. Объект типа Surface и его свойства Графические объекты типа surface представляют собой криволинейные поверхности, заданные таблично, — узлами сетки размерности mxn, заполняющей на плоскости ху прямоугольную область, и массивом z той же раз-
428 Глава 10 мерности, представляющим значения функции в узлах этой сетки. Если сетка па плоскости ху имеет регулярный шаг вдоль каждой из осей, то она может быть задана двумя векторами: х размерности п и у размерности т. В общем случае узлы сетки могут быть нерегулярными и тогда ее могут представлять двумерные массивы х и y с количеством элементов гоХп. Даже в случае регулярного задания узлов сетки бывает выгодно отказаться от векторов и воспользоваться двумерными массивами х и y, т. к. это может облегчить и ускорить процедуру формирования значений элементов массива z. Пусть, например, на оси хзаданы значения [-2, о, 2], а на оси у — значения [о, 1, 2, з]. Тогда для формирования двумерных массивов, представляющих сетку, можно воспользоваться функцией meshgrid (пример 10.]). I Пример 10.1. Формирование двумерного массива с помощью , "* "" '' ;** I | функции meshgrid ; .. „ ■■*?"' "" ! » u=[-2f 0, 2] ,- » v=[0,1,2,3],• » [X,Y)=meshgrid(u,v) X = -2 0 2 -2 0 2 -2 0 2 -2 0 2 У = 0 0 0 1 1 1 2 2 2 3 3 3 » Z = Х.*ехр(-Х.Л2 -У.Л2) Z = -0.0366 0 0.0366 -0.01-35 0 0.0135 -0.0007 0 0.0007 -0.0000 0 0.0000 Проигрыш в памяти из-за повторяющихся строк в массиве х и повторяющихся столбцов в массиве у компенсируется простотой и эффективностью вычисления значений функции z=-x*exp(x~2+y~2) в узлах сетки. Этот подход гарантирует и правильность сочетания координат х и у в узлах сетки.
Визуализация трехмерных объектов 429 Если массивы х, y и z сформированы тем или иным способом, то для создания и одновременного отображения объекта типа surface можно прибегнуть к услугам одной из функций — surf или mesh: » h_Surf = surf(X,Y,Z>; » h_Surf = mesh(X,Y,Z); Каждая из этих функций допускает много разных вариантов вызова, отличающихся наборами входных параметров, и возвращает указатель на созданный объект. Владельцем созданного объекта являются оси координат (объект типа Axes). Способ отображения созданной поверхности у каждой из перечисленных функций тоже разный, но эти детали более подробно обсуждаются в следующих разделах. На рис. 10.1 представлен вариант отображения, Построенный С ПОМОЩЬЮ ФУНКЦИИ mesh. 0.04 002- 0- -0.02. -0.04, 3 _,_. -Г""'"'"'. Ось Y 0-2 V-. ■—~"0 Ось 7 ""2 Рис. 10.1. Маркировка осей по значениям координат Вообще говоря, в простейшем случае каждой из этих функций достаточно передать только массив г. Но тогда вместо маркировки осей х и у значениями соответствующих координат будут использованы их индексы от 1 до m по оси х и от 1 до п по оси у (рис. 10.2). » h_Surf = mesh(Z); » ХЪаЬеМ'Ось X' >, YLabel ('Ось Y') По рис. 10.1 и 10.2 заметно, что элементы отображаемой поверхности окрашиваются в разные цвета. По умолчанию действует следующий алгоритм выбора цвета для вершин, ребер или граней поверхности. Все отображаемые элементы упорядочиваются по возрастанию координаты z характерной точ-
430 Глава 10 ки (для вершины — это табличная точка, для ребра — аппликата середины, для грани — аппликата точки пересечения диагоналей). Затем им присваиваются индексы цвета (одинаковым значениям z присваивается один и тот же индекс) и по этому индексу выбираются компоненты цвета из массива coiormap, установленного в данный момент для графического окна (объекта типа Figure). Если нас не устраивает выбор цвета по высоте аппликаты, мы можем при создании поверхности добавить в список аргументов еще один массив с размерности mxn, который сформирует значение свойства cnata- (более подробно свойство CData описано в разд. 7.7) и изменит способ окраски элементов поверхности: » h_Surf = surf(X,Y,Z,C); Рис. 10.2. Маркировка осей с использованием индексов координат Среди многочисленных параметров функций, создающих и отображающих поверхности, могут присутствовать пары "свойство — значение", инициализирующие значения соответствующих свойств. В примере 10.2 приводится полный перечень свойств объекта типа Surface. » get(h_Surf) » get(h_Surf)
Визуализация трехмерных объектов 431 AlphaData: 1 AlphaDataMapping: 'scaled' CData: [4x3 double] CDataMapping: 'scaled' EdgeAlpha: 1 EdgeColor: "flat1 EraseMode: 'normal' FaceAlpha: 1 FaceColor: [111] LineStyle: '-' LineWidth: 0.500.0 Marker: 'none' MarkerEdgeColor: 'auto' MarkerFaceColor: 'none' MarkerSize: 6 MeshStyle: * both' XData: [1 2 3] YData: [4x1 double] ZData: [4x3 double] FaceLighting: 'none' EdgeLighting: 'flat' EackFaceLighting: 'reverselit' AmbientStrength: 0.3000 DiffuseStrength: 0.6000 SpecularStrength: 0.9000 SpecularExponent: 10 SpecularColorReflectance: 1 VertexNormals: [4-x3x3 double] NormaIMode: 'auto' BeingDeleted: 'off But tonDownFcn: [] Children: [0x1 double] Clipping: 'on' CreateFcn: [ ] DeleteFcn: [] BusyAetion: "queue1 HandleVi s ibi1i ty: 'on' HitTest: 'on' Interruptible: 'on'
432 Глава 10 Selected: 'off SelectionHighlight: 'on' Tag: " Type: 'surface' UIContextMenu: [J UserData: [J Visible: 'on' Parent: 151.0018 DisplayName: '' XDataMode: 'auto' XDataSource: '' YDataMode: 'auto' YDataSource: '' CDataMode: 'auto' CDataSource:.'' ZDataSource: '' Кроме знакомых по гл. 7 свойств, появилось несколько групп специфических свойств, большинство из которых будет описано ниже. 10.2.2. Отображение проволочного каркаса поверхности Проволочный каркас (wire frame) поверхности образуется путем соединения точек поверхности с ближайшими соседями отрезками прямых. Для отображения каркасной поверхности используется одна из функций: mesh, meshc или meshz, допускающих различные варианты вызова. Программа, приведенная в примере 10.3, строит каркас функции на квадратной сетке с шагом о.?з. Этот шаг достаточно велик для получения качественного изображения, но он позволяет рассмотреть некоторые детали, связанные с удалением невидимых линий. Обращение к функции meshgrid с одним аргументом эквивалентно обращению с заданием двух одинаковых диапазонов. Команда coiorbar строит рядом с полем графика столбик с цветовой гаммой, соответствующей текущему состоянию массива coiormap. Маркировка столбика демонстрирует привязку цвета к значениям аппликат z. ) Пример 10.3. Построение каркаса функции и*?-х*ехр (хА2+уА2)^■ri^^'i^l » [X,Y] = meshgrid([-2:.25:21); » Z = Х.*ехр(-Х.л2 -У.л2); » mesh(X,Y,Z)
Визуализация трехмерных объектов 433 >> co.lormap(coo.l), colorbar » XLabeK'Ocb X') , YLabel ('Ось V),ZLabel('Ось Z'] 0.5. N js 0. и О -0.5, 2 <*>.&£% h OcbY "2 "2 -r-^"^ 0 -1 ОсьХ 4 2 iy • 0.4 0 3 0.2 0.1 0 -0.1 -0.2 -0.3 -0.4 Рис. 10.3. Проволочный каркас поверхности Рис. 10.4. Каркас с невидимыми линиями
434 Глава 10 Результат работы приведенной программы показан на рис. 10.3. По умолчанию функция mesh удаляет невидимые линии. Но если по какой-то причине удаленные линии необходимо восстановить, то достаточно выполнить команду hidden off. Соответствующий каркас показан на рис. 10.4. Возможно, что при отображении очень простых фигур типа пирамид или параллелограммов невидимые линии могут оказаться полезными. Но на насыщенном изображении их присутствие затрудняет восприятие. С помощью функции meshc строится каркас поверхности, дополненный линиями уровня z (х, y)=const, спроектированными на плоскость ху (рис. 10.5). Рис. 10.5. Каркас поверхности с линиями уровня Дополнительные детали, связанные с воспроизведением линий уровня, рассматриваются в разд. 10.2.4. Функция raeshz опускает из каждой граничной точки каркаса перпендикуляр на плоскость ху (рис. 10.6). При достаточно мелком шаге сетки создается впечатление занавеса, опущенного по краям изображения. Воспользуемся возможностью задания параметров в виде пар "свойство — значение" для принудительной окраски ребер: » rp.esh(X,Y,Z, 'EdgeColor', 'black') Результат такого воздействия на каркас приведен на рис. 10.7.
Визуализация трехмерных объектов 435 -'~~*~' ! ""*■■* --"!*"" ' '*"•* 0.5^.-—""'• 0- -0.5S --'■■""Vir - г i j _ " L-J J ! 2 --ОЧ : : : ---. : : : т>. i : *7^_ '• '• ''- _:;-^г\ ч 7-.-' ,-- "Г -V-r^- ^i T.~:-" "'L'-.<r , ^'" .v-;~- .".""" --~\' 1 *bi"—v . . .' i ■ ?Л~Л*><>'" i f-*4^ ,. ■■■.'--'-^■i—W'"^ ; -,<%^<.j>, l !Г г 1^-' И I'M >^yj ' :.* ': l .... ! l i i^r 1 I f ! 1 : i ! X I 1.: -"""o -1 N<---" -1 -2 -2 Рис. 10.6. Каркас поверхности на "постаменте" 0.5^ С -0.5> 2 -к ,---. ....-:-— _.--*'* ; • ■-^ i "■--.,. ?"5^J ^^^^Ж ""•' VVv • ..-""" "_^^^¾?^?s=½5^s¾^^^'"''^ ^""Sv^ -2 -2 -..._ 2 Рис. 10.7. Монохромный каркас
436 Глава 10 10.2.3. Отображение закрашенных поверхностей Закрашивание каждой четырехугольной чешуйки поверхности осуществляется с помощью функций surf и surfc. Это позволяет значительно улучшить восприятие поверхности (рис. 10.8). По умолчанию каждая грань закрашивается одинаковым цветом в соответствии с высотой ее характерной точки, а ребра между гранями остаются черными. Рис. 10.8. Закрашенная поверхность С помощью команды shading способ закраски может .быть изменен. Эта команда допускает задание одного из трех режимов — faceted, interp или flat. По умолчанию считается установленным shading faceted. Это приводит к закрашиванию каждого участка поверхности, ограниченного четырьмя точками, своим цветом и отображением между ними черных ребер (если иное не задано в свойствах объекта при вызове функции surf). В режиме flat ребра не отображаются, а в режиме interp выполняется еще и сглаживание цветов между соседними участками поверхности. Режим imierp соответствует применению алгоритма закраски Гуро, при котором осуществляется билинейная интерполяция цветов внутри каждой грани и между соседними гранями (рис. Ю.9). Ребра при этом не рисуются, и создается видимость сплошной поверхности. В режиме fiat, грани тоже не
Визуализация трехмерных объектов 437 воспроизводятся, но цвета граней сохраняются. За счет этого смежные грани одного цвета объединяются в более крупные образования. Рис. 10.9. Закрашенная поверхность (после команды shading interp) 10.2.4. Управление точкой зрения Позиция наблюдателя, из которой мы рассматриваем изображение поверхности, в системе MATLAB носит название позиции камеры (camera posiiion) или точки зрения (view point). Если с позицией камеры и другими ее характеристиками связано довольно много свойств, то точка зрения характеризуется всего двумя углами — азимутом (Azimuth) и углом возвышения (Elevation). Первый из них определяет угол поворота вокруг оси г и отчитывается от отрицательного направления оси у против часовой стрелки. Второй угол образован отрезком прямой, соединяющей точку зрения с началом координат, и плоскостью ху (рис. 10.10). Удаление от предмета наблюдения в расчет не принимается. По умолчанию для этих углов установлены следующие значения: Azimuth = -37.5Q Elevation = 30°
438 Глава 10 С помощью функции view можно управлять точкой зрения и. тем самым, менять внешний вид изображения (пример 10.4). Пример 10.4; Управление точкой зрения fpj* - ■»■"'. - >■ » view(az,el) » view![az, el]) » view([x,y,z]) » [az,el] = view; » view (2 J » view(3> Точка зрения -У Рис. 10.10. Положение точки зрения Первые два варианта эквивалентны. Их аргументами являются азимут и угол возвышения. Обращение view и, у, z) задает декартовы координаты точки зрения. Вызов функции view без параметров позволяет опросить параметры текущей точки зрения. Сокращенные варианты вызова функций view(2) и yiew(3) устанавливают значения азимута и угла возвышения по умолчанию для плоских (az=o, el=so°) и объемных (az=-37.5°, е1=зо°) изображений. 10.2.5. Выбор алгоритма визуализации На рис. 10.11 изображены несколько объектов типа сфера. Верхний ряд построен при локальном освещении, нижний — при бесконечно удапенном
Визуализация трехмерных объектов 439 источнике света. Чем дальше от объекта находится источник света, тем меньше размер зеркального пятна, наблюдаемого в месте встречи с более короткими лучами. Однако на последнее гораздо большее влияние оказывают свойства, управляющие отражающими характеристиками поверхности (specular-Strength, SpecularExponent, SpecularColorReflectance). Сфера относится к группе объектов типа surface. Таблица каркасных координат сферы создается с помощью функции sphere: [х,у,z]=sphere; [х#у,z3=sphere{N); Здесь м — количество узлов по каждой из координат (по умолчанию N=20). В построениях на рис. 10.11 использованы три варианта окраски граней: П FaceLighting=gourand — окраска точек каждой грани интерполирована по схеме Гуро (сферы 1,4); П cac.eLighting=fiat — окраска всех точек каждой грани фиксирована (сферы 2, 5); П FaceLighting=none — все грани поверхности окрашены в один и тот же цвет (сферы 3, 6). rap;. -* - ■ -ft '■?*. 1 J№ if- . 1-1. 4 - Oi 2 5 *Щ& 1,. ,f „ . •"--■■- „X0S ■'.-: 1] I. 3 л " ? 6 Рис. 10.11. Использование различных алгоритмов закраски с разными источниками света Четвертый возможный вариант FaceLighting=phong (интерполяция окраски по схеме Фонга) здесь не приведен, т. к. даже в цветном варианте на примере этой сферы он дает результаты, почти не отличающиеся от алгоритма Гуро. I 5 Зак. 849
440 Глава 10 10.2.6. Освещение поверхностей Источник света — объект типа Light — оказывает влияние на отображение трехмерных поверхностей и тел, представленных объектами типа Surface и Patch. Создается он с помощью функции light: hL=li ght('Свойство_1',Значение_1,'Свойство_2',Значение_2,...); К числу наиболее важных свойств источника света относятся: П color. — определяет цвет источника путём задания удельного веса RGB- составляющих в каждом луче, исходящем из источника; П style — определяет тип источника и может принимать одно из двух значений: • styie=inf inity (бесконечно удаленный источник); • styie=iocai (локальный источник); П Position — задает координаты положения локального источника света ([х; у; г]) или вектора, направленного в сторону бесконечно удаленного источника. С помощью функции lightangie можно установить, изменить или опросить значения углов азимута и возвышения источника света (пример 10.5). ; Пример 10.5. Установка и проверка/значении углов^азимута г||*; «*- •■-Ф '?$Щ$^Д i и возвышения источника света V, -. ^¾¾¾^¾3^ .*.- .жйл*™ ^C^s»*-^i » hL=lightangie(О,30); » lightangie(hL,90,30); » [az,el]=lightangle(hL) az = 90 el = 30.0000 Источник света приписывается объекту типа Axes и оказывает влияние только на дочерние объекты этих осей. Бесконечно удаленный источник света излучает пучок параллельно направленных лучей, обладающих одинаковой интенсивностью освещенности. От локального источника лучи равномерно распространяются во все стороны. У объекта типа Axes может быть несколько источников света. По умолчанию оси снабжаются бесконечно удаленным источником белого света. Его угол возвышения совпадает с углом возвышения позиции наблюдателя, а азимут на 45° больше азимута наблюдателя.
Визуализация трехмерных объектов 441 Существует также полезная функция camiight, создающая источник света с координатами, совпадающими с координатами точки зрения, или находящийся рядом с ней: □ camiight headlight — создает источник, совпадающий с точкой зрения; П camiight right — создает источник правее и выше точки зрения; П camiight left — создает источник левее и выше точки зрения; П camiight — эквивалентно camiight right; П camiight(az,el) — азимут и угол возвышения по отношению к точке зрения; П camiight(... 'style') — дает возможность задать тип источника (local ИЛИ infinite); П camiight (iight_handie, ...) — использует источник с заданным указателем; П lighthandie = camiight (...) — возвращает указатель на источник. Отображение поверхности, освещенной источником света, во многом зависит от свойств "материала" поверхности. Обратите внимание, что эти свойства начинают работать только после создания в текущих осях источника света. Для задания этих параметров используются уже упомянутые выше свойства поверхности, управляющие отражающей способностью, — specuiarstrength, SpecularExponent, SpecularColorReflectance. Кроме ТОГО, существуют И другие свойства: П Ambientstrength — интенсивность влияния рассеянного света. Цвет рассеянного света Задается В свойстве AmbientLightColor объекта Axes. Принимает значение от о до 1; П Diffusestrength — степень диффузного рассеивания света от источника. Принимает значение от о до i; О Specuiarstrength — интенсивность отражения света от источника. Принимает значение от о до 1; П SpecularExponent — параметр, управляющий размером светового блика. Должен всегда превышать 1. Для большинства встречающихся в природе материалов значение попадает в диапазон от 5 до 20; П SpecularColorReflectance — степень влияния цвета поверхности на цвет блика. Принимает значение от о до 1. При о цвет блика является смешанным цветом источника света и поверхности. При 1 цвет блика определяется исключительно цветом источника света.
442 Глава 10 Типичные отражающие параметры поверхностей могут быть заданы командой material, управляющей описанными выше свойствами: П material shiny — блестящая поверхность; П material dull — матовая поверхность; П material metal — "металлическая" поверхность; П material ([ka kd ks]) — устанавливает всем объектам одинаковые значения СВОЙСТВ AmbientStrength(ka), DiffuseStrength(kd), SpecularStrength(ks); П material ( [ka kd ks n]) —TO же Самое, ПЛЮС SpecularExponent (n); П material ([ka kd ks n sc] ) — то же, что предыдущее, плюс свойство SpecularColorReflectance(sc); П material default — возврат к значениям по умолчанию. Следует отметить, что лучше всего разница видна при использовании алгоритма визуализации Фонга (FaceLighting=phong). К тому же материал поверхности в этом случае выглядит более правдоподобно. 10.2.7. Построение линий уровня Под линиями уровня, или изолиниями, понимают кривые, получающиеся в результате пересечения поверхности г(х,у) с плоскостями z=const. Эги линии можно спроектировать на одну плоскость и получить 20-изображение, а можно воспроизвести как пространственные кривые и построить 3D- изображение. Наглядным примером 20-изображения изолиний являются линии рельефа поверхности на топографических картах. По ним можно легко локализовать вершины и впадины, оценить их высоты и глубины, особенно, если в разрывах изолиний проставлены числовые значения соответствующих уровней. К числу наиболее употребительных функций, связанных с отображением ЛИНИЙ уровня, ОТНОСЯТСЯ contour, contourf, contourc, contour3 И clabel. Функция contour используется для построения проекций линий уровня на плоскость ху и допускает несколько вариантов вызова: contour (Z) contour(Z,k) contour(Z, v) contour(X,Y,Z) contour(X,Y,Z,k) contour (X, Y, Z, v) contour(...,'Свойство_1',Значение_1, ...)
Визуализация трехмерных объектов 443 В любом случае двумерный массив z размерности mXn представляет аппликаты точек поверхности, по которым формируются и воспроизводятся контуры линий уровня. Массивы х и y могут быть векторами размерности п и га соответственно или матрицами той же размерности, что и г. Они задают координаты узлов сетки, в которых определены аппликаты поверхности. Если область определения поверхности квадратная и шаги по осям х и у совпадают, то вместо пары аргументов (х, y) может быть задан только один массив. Если задание координатной сетки отсутствует, то считается, что абсцисса х пробегает значения от 1 до п, а ордината у — от 1 до ш. Скалярная величина к залает количество уровней (т. е. количество высот по оси г), для которых должны быть построены изолинии (количество самих изолиний при этом может не совпадать с к, т. к. соответствующая плоскость может дать несколько разных линий пересечения с поверхностью). Если значение параметра к не задано, то количество уровней выбирается автоматически из интервала [zmin, zmax]. Обычно оно не превышает 20 и делится на 2 или 5. Вектор v определяет набор уровней, для которых должны быть построены изолинии. Если какие-либо его компоненты не принадлежат диапазону [zmin, zitiax], то соответствующих изолиний не существует. Функция contour, создающая графические объекты, наряду с описанными выше аргументами, допускает задание парных аргументов ("свойство — значение"). При любом варианте вызова функция contour может вернуть два массива: [С h]=contour(...); Массив с представляет матрицу с информацией о каждой изолинии. Его можно рассматривать как длинную таблицу, состоящую из двух строк. Первая колонка задает значение уровня изолинии и число содержащихся в ней точек, следом располагается указанное количество пар (х=, ул) с координатами точек изолинии. Вслед за первой изолинией в таком же формате располагается информация о второй изолинии и т. д. Этот массив понадобится в том случае, когда придется оцифровывать изолинии — включать в разрыв линии значение ее уровня. Вектор h представляет собой набор указателей на созданные графические массивы. Он тоже понадобится в качестве параметра для оцифровки изолиний. В примере 10.6 и на рис. 10.12 представлены проекции изолиний поверхности, которую мы рассматривали в разд. 10.2.3.
444 Глава 10 fПример 10.6: Создание проекций изолиниигпо'веркн6стй ^^¾¾^^¾.¾^^¾ » [X,Y] = meshgridt[-2:.25:2]); » Z = Х.*ехр{-Х.Л2 -У.л2); » colormap(cool) » contour(X,Y,Z, 20) 1.5 1 0.5 0 -0.5 -1 -1.5 -2 /' ... "'".. - Z ■ \ ■ S , _- " у , • / "'" "'_' A\\ /' ■«■■ . Ш ■Un- /i ~*'" "-■■..—v. „_-=""'" III v,—■^--..--o-.x - \ Щ5ЩУ 2-1.5-1-05 0 0.5 1 15 : 2 Рис. 10.12. Проекции изолиний поверхности С помощью функции contourf можно закрасить в разные цвета области, расположенные между смежными линиями уровня (пример 10.7, рис. 10.13). : Пример 10.7. Создание разноцветных областей мёад fc;yfy^Jp|;:] » colormap jet » contourf(X,Y,Z,10) Для оцифровки изолиний предназначена функция ciatoei, которой передаются два входных параметра — матрица изолиний и вектор указателей на линии уровня (пример 10.8). "Т"Т? 1 Пример 10.8. Автоматическая оцифровка изолиний » [C,h] = contour(X,Y,Z, 6) ; » colormap gray » clabel(C,h) Иг у.., :Л .*• <л -Г :
Визуализация трехмерных объектов 445 Рис. 10.13. Заливка областей между изолиниями В этом фрагменте использована серая полутоновая матрица цветности (colormap gray), а результат работы кода представлен на рис. 10.14. 1.5 1 0.5 0 -0 5 -1 -1.6 -2 ■ /-^% / ' ft % £gtf о rr & -°-o^er-- 2 -15 -1 -0.5 0 0.5 """■--,... .^ "% 1 - ^ C^ 1 1.5 : ? Рис. 10.14. Автоматическая оцифровка изолиний Автоматически выполненная оцифровка линий уровня выглядит не очень привлекательно, особенно в районе концентрации изолиний. Довольно трудно придумать алгоритм правильного выбора места размещения цифровой отметки.
446 Глава 10 Поэтому функция clabel предусматривает ручной режим оцифровки, на который можно выйти, задав дополнительный параметр (пример 10.9). Пример 10.9. Ручная оцифровка изолиний |||>; ™ЕГ ш «-•■ » [C,h] = contour (X,Y,Z, 6) ; » colormap gray » clabel(С,h,'manual') В этом случае на экране появляется графическое окно с неоцифрованными изолиниями. Однако с помощью мыши вы можете переместить перекрестье, направив его в точку выбранной изолинии, и после щелчка левой кнопкой в заданной точке появится соответствующая оцифровка. Ее центр совпадает с выбранной точкой. Пример ручной оцифровки показан на рис. 10.15. К сожалению, качество ручной оцифровки тоже оставляет желать лучшего — линии наезжают на оцифровку, угол наклона надписи иногда не совпадает с изгибами кривой, количеством отображаемых цифр управлять нельзя. 2 1.5 1 0.5 0 -0 5 и -1.5 I - I £ - I I \ N 2 -1.5 ^ ) I VJ I /" J ""■^__^ тт'~ -1 -0.5 0 ' —~~ 05 1 1 - \ 1 • 1'. -trf с#' 1 1.5 2 Рис. 10.15. Ручная оцифровка изолиний Функция contourc относится к категории низкоуровневых, к которой пользователь напрямую не обращается. Ее вызывают функции contour, contourf
Визуализация трехмерных объектов 447 и contour3. Функция строит матрицу с параметрами изолиний, которую возвращает в качестве результата своей работы: С = contourс(Z) ; С = contourc(X,Y,Z); Изолинии в пространственном исполнении отображаются функцией contour-з. Перечень ее входных параметров такой же, как и у функции contour. Результат работы команды contour3 (x,y, z, 20) приведен на рис. 10.16. Рис. 10.16. Изолинии в пространстве Для изменения свойств изолиний можно воспользоваться массивом указателей, который возвращает функция contour.3 (пример 10.10). ! Пример 10г10. Изменение толщины изолиний Т.?: --.,^-1 %' ^%.^--., ,J » [X,Y] = meshgrid([-2:.25:2]); >> 2 = Х.*ехр(-Х.А2 -У.Л2).; >> colormap copper » [C,h]=contour3(XfY,Z,6); » set(hr'LineWidth',2) % изменение толщины изолиний
448 Глава 10 Результат работы этого фрагмента, в котором толщина изолиний увеличена до 2 пунктов, приведен на рис. 10.17. Рис. 10.17. Утолщенные пространственные изолинии 10.3. Формирование и отображение полигональных тел 10.3.1. Объект типа Patch и его свойства Для построения полигональных тел (многофанников) используется функция patch. Считается, что многофанники состоят из офаниченного числа вершин (vertex) и фаней (Face). Каждая фань включает в себя 3 или более вершин. При различных способах задания вершин и фаней можно добиться того, чтобы вершины соединялись или не соединялись ребрами (Edge), входили в одну или несколько фаней или вовсе не использовались при построении. Существуют два основных способа построения фигур типа Patch: П путем задания координат вершин каждой грани, соединяя которые, MATLAB строит фигуру; П путем задания координат всех вершин многогранника и указания, какие из них следует объединить в грани с заданными номерами.
Визуализация трехмерных объектов 449 В первом случае формат вызова функции выглядит следующим образом: h_P = patch(X,Y,C) h_P = patch(X,Y,Z,C) Здесь x, y, z — это векторы значений х-, у- и ^-координат вершин многогранника (или многоугольника в случае отсутствия г-координат), а с — задает цвет в формате coiorspec. Аргументы х, y и z могут быть матрицами, тогда для каждого столбца строится свой многоугольник. В любом случае функция patch возвращает указатель на сформированный объект. Для того чтобы построить правильный восьмиугольник, можно воспользоваться фрагментом программы из примера 10.11. Г'Прийер 1^^^ •; т^'";^ ^1¾¾^¾ ./_*■£ » t=0:pi/4:2*pi; » X=sin(t); » Y=cos(t); » h_P = patch (X,Y, [1 0 0]) » axis equal В этом случае в векторах х и у мы получаем восемь пар координат (на самом деле 9, но первая и последняя точки совпадают) точек* равномерно расположенных на окружности единичного радиуса. Функция patch соединяет их и закрашивает полученный восьмиугольник красным цветом (рис. 10.18). Последняя строка делает масштаб по обеим осям одинаковым, чтобы многоугольник не казался сплющенным. 1 0.5 0 -0.5 -1 • -1 -0.5 0 0.5 1 Рис. 10.18. Плоский восьмиугольный Patch
450 Глава 10 В примере 10.12 приведены свойства построенного объекта. I Пример 10.12. Свойства восьмиугольника '\*Щ$ -¾ *■ "■'' ^""Ь^рВЩкт. » get(h_P) AlphaDataMapping = scaled CData = [] CDataMapping = scaled FaceVertexAIphaData = [] FaceVertexCData = [] EdgeAlpha = [1] EdgeColor = [0 0 0] EraseMode = normal FaceAlpha = [1] FaceColor = [1 0 0] Faces = [ (1 by 9) double array] LineStyle = - LineWidLh. = [0.5] Marker = none' MarkerEdgeColor = auto MarkerFaceColor = none MarkerSize = [6] Vertices = [ (9 by 2) double array] XData = [ (9 by 1) double array] YData = [ (9 by 1) double array] ZData = [] FaceLighting = flat EdgeLighting = none BackFaceLighting = reverselit AmbientStrength = [0.3] DiffuseStrength = [0.6] SpecularStrength = [0.9] SpecularExponent = [10] SpecularColorReflecuar.ee = [1] VertexNormals = [ (9 by 3) double array] Norma IMode- = auto BeingDeleted = off ButtonDownFcn =
Визуализация трехмерных объектов 451 Children = [3 Clipping = on CreateFcn = DeleteFcn = BusyAction = queue HandleVisibility = on HitTest = on Interruptible = on Parent = [lOl'.OOl] Selected = off SelectionHighlight = on Tag = Type = patch UIContextMenu = [] UserData = [] Visible = on Задавая достаточно большое количество точек, можно получать на экране плавные кривые, окружности, эллипсы. Приведенный пример 10.13 строит на экране изображение круга, окрашенного плавно изменяющимися цветами (рис. 10.19). ! Пример 10.13. Построение круга с плавной заливкой » t=D:0.01:2*pi; » X=sin[t); » Y=cos(t>; » patch (X,Y, [1 0 0]) » axis equal » patch(X,Y,1: length(t)) Координаты вершин можно задавать не только как позиционные аргументы функции patch, но и с помощью свойств xdata, Ydata, zdata Создаваемого объекта: h_P = patch('Xdata',X,'Ydata',Y) В простых случаях координаты точек многоугольника можно задавать непосредственно в цифровом виде. Пример 10.14 строит на экране желтый прямоугольный треугольник с катетами, лежащими на осях координат ('у' — константа, задающая желтый цвет — от англ. yellow).
452 Глава 10 1 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 -0.8 . *■ ий^'1' &**■ 'Р-! ' т#&. ■ 1 ■ т£ - ■ К \ jT л- •■ \ '"" \ \ i i ^~~—— -1 -0.5 ;-. :?„-:■ ■ >■ S4* ■'• ЩУ^ ^¾¾ ■ '/* :Vf ,*t > -^#,-, v4# .. W ;f\X 0 0.5 1 1 Рис. 10.19. Плоский 628-гранный Patch ^Пример 10.14..Построение желтого треугольника ,-.¾ | - * :j'fti,""*w4^ >,.^*дай§£я » X = [0 1 0J; » Y = [0 0 1] ; » patch(X,Y,'у') Для того чтобы построить таким же способом многогранник, придется задавать х, y и z в виде матриц, в которых для каждого столбца будет построен свой многоугольник. Рассмотрим это на примере одного из простейших случаев — попробуем нарисовать куб (рис. 10.20). Так как куб состоит из 6 фаней, то матрицы будут содержать 6 столбцов. Каждая фань состоит из четырех вершин, поэтому в каждой матрице будет 4 строки. Попробуем непосредственно записать значения (х, у, z) для вершин куба и построить необходимые матрицы. В табл. 10.1 зафиксированы значения координат вершин, образующих все 6 фаней куба. Рассмотрим заполнение таблицы на примере лицевой фани, лежащей в плоскости xz. Грань образована вершинами со следующими координатами: (0, 0, 0), (1, 0, 0), (1, 0, 1), (0, 0, I). Соответственно вектор значений х-координат для построения этой грани будет иметь вид (0, 1, 1, 0). Он соста-
Визуализация трехмерных объектов 453 вит первый столбец матрицы х-координат. Аналогично для ^-координат: (О, 0, 0, 0), для г-координат: (0, 0, 1, I). Проделав такую же работу для остальных граней, заполняем все матрицы. Теперь каждый столбец соответствует своей грани. (о, о, 1) (0, о, 0) (1,1.1) (1.0,0) Рис. 10.20. Цциничный куб с координатами вершин Матрица х-координат 0 1 1 0 1 1 1 1 0 1 1 0 0 0 0 0 0 1 1 0 0 1 1 0 Матрица у-координат 0 0 0 0 0 1 1 0 0 0 1 1 0 0 1 1 0 0 1 1 1 1 1 1 Таблица 10.1 Матрица г-координат 0 0 1 1 0 0 1 1 1 1 1 1 0 1 1 0 0 0 0 0 о 0 1 1 Проверяем результат (пример 10.15). ! Пример 10.15. Проверкаi содержимого ма^ртц^Ч^й^ ^ч.^; » Х=[0 10 0 0 0; 111011; 111011; 010000]; » Y=[0 00001; 010001; 0 11111; 001111]; » Z=[0 010 0 0; 00 110 0; 1 1110 1; 111001]; » patch(X-,Y,Z, [0.5 0.5 0.5]) » axis equal » view(3) *ш*
454 Глава 10 Последняя команда устанавливает проекцию, используемую по умолчанию для визуализации трехмерных объектов. Если этой команды не будет, то мьг увидим только одну грань куба, лежащую в плоскости ху, — команда patch по умолчанию устанавливает двумерный вид в создаваемых при своем вызове осях. Результат работы программы — на рис. 10.21. Рис. 10.21. Единичный куб Теперь попробуем построить тот же куб вторым способом — задав матрицу координат вершин и указав, какие из них необходимо объединить в грани. В этом случае матрицы будут выглядеть следующим образом. Матрица вершин v имеет три столбца — для х-, у- и z-координат вершим соответственно. Поскольку у нас 8 вершин, то в матрице v окажется 8 строк и она будет иметь следующий вид: » V= [0 0 0;1 0 0;1 0 1;0 0 1;0 1 0;1 1 0;1 1 1;0 1 11; Теперь необходимо построить матрицу F, в каждой строке которой будут перечислены вершины, образующие соответствующую грань. Вершина задается как номер строки матрицы v, содержащей координаты этой вершины. Так как граней всего 6, то в матрице f появятся 6 строк, а поскольку каждая грань включает в себя 4 вершины, то в ней будет 4 столбца: » F=[l 2 3 4;1 2 6 5;2 3 7 6;1 6 8 5;3 4 8 7;5 6 1 S];
Визуализация трехмерных объектов 455 Проверяем: »" patch! 'Vertices' ,V, 'Faces', F, 'FaceColor', [0,5 0.5 0.5]) »■ axis equal >> view (3) Результат работы программы полностью эквивалентен предыдущему способу построения многогранников. Однако в последнем случае для построения куба нам потребовался значительно меньший объем данных. В первом случае нам пришлось сформировать три массива размерностью 4x6, т. с. по 24 элемента. Во втором случае таких массивов потребовалось всего два. К тому же построение фигур вторым способом более наглядно. 10.3.2. Закрашивание объектов типа Patch Для того чтобы окрасить многоугольник или многогранник, построенный с помощью функции patch, можно кроме описанных выше способов использовать свойства, приведенные в табл. 10.2. Объекты Patch в отличие от объектов Surface не могут автоматически генерировать значение цвета в зависимости от значения ^-координаты каждой вершины. Цвет граней можно задать одним из трех следующих способов: П одинаковый цвет для всех граней; □ свой цвет для каждой грани; П свой цвет для каждой вершины, используемый для плавных переходов цвета. В процедуре закрашивания объектов типа Patch могут принимать участие и ребра — линии, соединяющие смежные вершины многогранника и отделяющие грани одну от другой. Их окраска может быть задана одним из трех аналогичных вариантов: П одинаковый цвет" для всех ребер; □ свой цвет для каждого ребра, определяемый цветом соответствующей вершины; П плавный переход цвета между точками ребра, определяемый цветом соответствующей пары вершин. Таблица 10.2 Свойство Значение CData Определяет свой цвет для каждом грани или вершины на основании данных о координатах вершин CDataMapping Определяет, каким образом масштабируются цветовые данные
456 Глава 10 Таблица 10.2 (окончание) Свойство Значение FaceVertexCDa.ta Определяет свой цвет для каждом грани или вершины на основании данных о вершинах и гранях EdgeColor Задает общий цвет для всех ребер или способ их отображения: видимые, невидимые, с плавными переходами цвета FaceColor Задает общий цвет для всех граней или способ их отображения: видимые, невидимые, с плавными переходами цвета MarkerEdgeColor Определяет цвет маркеров или цвет контура у закрашенных маркеров MarkerFaceColor Определяет цвет закраски маркеров Рассмотрим некоторые свойства подробнее. П Свойство CData. С помощью свойства CData можно задавать цвета для каждой вершины, каждой грани или определить цвет для фигуры в целом. Требуемое действие MATLAB производит в зависимости от типа данных. Цвет может быть задан в виде индекса цвета в цветовой палитре, . либо в виде цветовых составляющих RGB в формате truecolor. Цветовую палитру можно отобразить рядом с рисунком с помощью команды coiorbar. Более подробно задание цвета с помощью свойства CData обсуждалось в разд. 7.7. Рассмотрим случай с индексами цветов. Если значением CData является число, то вся фигура будет закрашена цветом, соответствующим заданному индексу. Для того чтобы каждой грани присвоить свой цвет, потребуется матрица с единственной строкой, в которой каждое значение будет определять цвет соответствующей грани. Рассмотрим пример 10.16. ! Пример 10.16. Монотонное.закрашивание граней куба .-: .,; .::J^~4^ui;i**^^# » Х=[0 1000 0; 111011; 111011; 01000 0]; » Y= [0 0 0 0 0 1; О 1 0 0 0 1; 0 1 1 1 1 1; 0 0 1 1 1 1] ; » Z=[0 0 1 0 0 0; 0 0 1100; 111101; 111001]; » С=[1 2 3 4 5 6]; » h=patch (X, Y, Z, ' у ■) ; » set(h,'CData',С,'FaceColor','flat') » coiorbar » axis equal » view(3)
Визуализация трехмерных объектов 457 Результат работы этого фрагмента представлен на рис. 10.22. Рис. 10.22. Куб с разноцветными гранями Для того чтобы закрасить разными цветами каждую вершину, придется задать матрицу размерностью, соответствующей матрицам х-, у- и z- значений (для куба 4x6). Тогда каждой вершине будет поставлен в соответствие свой цвет. Поскольку в нашем случае вершины участвуют в образовании нескольких граней одновременно, то и данные в матрице CData для них должны совпадать. В случае задания цветов в формате RGB приходится вместо одного значения указывать три и в последнем случае (для задания цвета каждой вершины) нужно формировать трехмерный массив 4x6x3, где в трех матрицах размерностью 4x6 хранятся значения цветовых составляющих R, G и В для каждой вершины. П Свойство FacevertexCData. Более наглядно выглядит способ задания цветовых данных с помощью свойства FacevertexCData. В зависимости от типа данных, используемых для задания значения свойства, применяются различные способы закрашивания. В случае если матрица содержит один столбец, то ее значения рассматриваются как индекс цвета в цветовой палитре. Если значением является число, то вся фигура будет закрашена одним цветом. Когда матрица значений FacevertexCData содержит три столбца, то ее значения интерпретируются как цветовые компоненты RGB в формате truecolor. Количество строк в матрице может соответствовать либо коли-
458 Глава 10 честву вершин, либо количеству граней. Если в матрице всего одна строка, то вся фигура будет закрашена одним цветом. С случае, когда число строк равно числу граней в многограннике, каждая грань будет окрашена в цвет, закодированной в строке матрицы FaceVertexCData с номером, соответствующим номеру грани. Рассмотрим окрашивание куба (пример 10.17). Пример 10.17. Окрашивание куба ' "... ^¾¾¾^.¾¾^ %S;'' "'".:! » V=[0 0 0; 1 0 0; 1 0 1; 0 0 1; 0 1 0; 110; 111; 0 11]; » F=[l 2 3 4; 1 2 6 5; 2 3 1 6; 1 4 8 5; 3 4 8 7; 5 6 7 8]; » FVCD=|1 0 0; 0 1 0; 0 0 1; 1 1 0; 1 0 1; 0 1 1| ; » patch('Vertices',V,'Faces',F,'FaceVertexCData', FVCD,'FaceColor','flat') » axis equal » view(3) В случае, когда количество строк в матрице fvcd совпадает с количеством вершин, цветовые значения будут присвоены вершинам. Если при этом значение свойства FaceColor как и в предыдущем случае окажется flat, то каждой грани будет присвоен цвет вершины, с которой начинается ее построение. Поэтому после работы следующего примера некоторые грани будут окрашены одинаково: » V=[0 0 0; 1 0 0; 1 0 1; 0 0. 1; 0 10; 110; 11]; 0 11]; » F=[l 2 3 -5; 1 2 б 5; 2 3 7 6; 1 4 8 5; 3 4 В 7; 5 б 7 8] ; » FVCD=[1 0 0; 0 1 0; 0 0 1; 1 1 0; 1 0 1; 0 1 1; 0.5 0.5 0; 0.5 0 0.51; » patch('Vertices',V,'Faces',F,'FaceVertexCData', EVCD, 'FaceColor', 'flat') » axis equal » view(3) Кстати, свойство FaceColor лучше всегда задавать, чтобы избежать неожиданных результатов на экране (например, грани не отображаются). Чтобы избавиться от одноцветных граней, придется изменить порядок указания вершин в матрице f так, чтобы все грани начинались с разных вершин: » F=[l 2. 3 4; 6 5 1 2; 2 3 7 б,- 4 8 5 1; 3 4 8 7; 5 6 7 8]; Теперь у нас получится такой же разноцветный кубик, как и на рис. 10.23, только порядок цветов слегка будет отличаться. Однако способ задания цветов для каждой вершины позволяет добиться некоторых дополнительных возможностей при закрашивании.
Визуализация трехмерных объектов 459 К 0 8- 0.6- 04- 0.2- о> 1 \^\ 0.5^- 0 - *" 0 0.5 1 Рис. 10.23. Куб с окрашенными гранями 1 0.8 0.6 0.4 0.2 0 1 £■"■.)" ■"%■ -¾ .С*й< 0.5 ^«■.1* "| . ^л. ^ , -^-^5^^.:.--- - ->tf- .. i - ? Iff . ■&, ■ 1¾^ ■ 3 ж. ?-i ,. ai iff о" e ■ ^^. •^ 1 0.5 Рис. 10.24. Куб с плавными переходами цвета и видимыми ребрами
460 Глава 10 Замена значения свойства FaceCoior на interp позволяет добиться плавного перехода цветов на гранях: patch('Vertices',V,'Faces',F,'FaceVertexCData', FVCD,'FaceCoior','interp') Если одновременно значением свойства EdgeCoior будет flat, то на фоне плавных переходов цветов граней будут видны разноцветные ребра (рис. 10.24). 10.4. Специальные способы закраски. Прозрачность 10.4.1. Нанесение изображения на поверхность Задачи трехмерной графики часто требуют нанесения на поверхность сложного узора или графического изображения. Сформировать в таком случае с помощью ручного ввода или математических методов содержание для свойства CData представляется слишком трудоемкой задачей. Гораздо удобнее воспользоваться графическим объектом типа image. И MATLAB представляет для этого простые и удобные средства. Попробуем с ними познакомиться на примере задачи "натягивания" графического изображения на сферу. Построим сферу, получим на нее указатель и загрузим графическое изображение из файла (пример 10.18). ! Пример 10.18. Построение сферы ч ■ ' * --."'"-' '■"■''' ^1^^]¾¾^1^^^ » sphere » h=findobj['Type','surface'); » a=imread('с:\Downloads\mask.jpg'); » whos Name Size Bytes Class a 272x272x3 221952 uint8 array h lxl 8. double array Grand total is 221953 elements using 221960 bytes Как видно, объект тина image содержит изображение в формате truecolor размером 272x272 пиксела. Для "натягивания" изображения на сферу достаточно установить следующие свойства: » set(h,'CData',a,'FaceCoior','texturemap') » view ([-85 40])
Визуализация трехмерных объектов 461 К сожалению, изображение получилось перевернутым вверх ногами (кстати, MATLAB всегда переворачивает изображение). Так что повернем сферу вокруг оси х на 180° (рис. 10.25): » rotate(h,[1 0 0],180) Заметим, что в данном случае не действует привычное правило о том, что каждой вершине или грани соответствует одно значение свойства cData. Мы специально оставили видимыми ребра сферы, чтобы легче было заметить, что каждый пиксел изображения (т. е. каждое значение свойства CData) соответствует пикселу визуализированного изображения сферы. В системах трехмерного моделирования такой способ задания цвета носит название texture mapping. В результате изображение масштабируется и подстраивается под реальный размер трехмерного объекта на экране. Рис. 10.25. Изображение, "натянутое" на сферу Обратите внимание, что такой способ закраски действует только в отношении поверхностей, т. е. объектов типа surface. К объектам типа Patch такая схема неприменима.
462 Глава 10 10.4.2. Прозрачные поверхности В общем случае прозрачность всех объектов в текущих осях можно регулировать функцией alpha. Формат обращения к ней следующий: alpha (tace_alpha) alpha(alpha_data) alpha(alpha_data_mapping) alpha(object_handle,...) В первом случае при задании значения face_aipha можно задать степень прозрачности всех объектов типа image, Patch и surface. Значения могут быть следующими: П число — устанавливает степень прозрачности в диапазоне от о до i; П 'flat' — каждая грань имеет одинаковую степень прозрачности; П 'interp' — каждая грань имеет изменяющуюся степень прозрачности; □ 'texture' — прозрачность каждой грани задается набором данных типа Image; П 'opaque' — все объекты полностью непрозрачные; П 'clear' — все объекты полностью прозрачные. В случае установки параметров 'fiat', 'interp' и "texture" потребуется также определить у объектов свойство AlphaData, размер которого должен совпадать с размером ZData. Аргумент aipha_data может принимать следующие значения: П матрица — непосредственно устанавливает значение свойства AlphaData; П 'х' — устанавливает значение AlphaData совпадающим с XData; П 'у' — устанавливает значение AlphaData совпадающим с YData; О V — устанавливает значение AlphaData совпадающим с ZData; П 'color' — устанавливает значение AlphaData совпадающим с cData; Р 'rand' — устанавливает случайные значения для прозрачности. Пример сферы, построенной по умолчанию после команды alpha {'г,'), приведен на рис. 10.26. Свойства прозрачности имеют много общего со свойствами цвета. Можно оперировать как с непосредственными значениями прозрачности, заданными в форматах double или uinte, так и пользоваться индексами в шкале прозрачности alphamap, являющейся аналогом eolormap.
Визуализация трехмерных объектов 463 С помощью функции alpha можно управлять значением свойства AlphaDataMapping у всех объектов в текущих осях: П 'попе' — в этом случае значения массива AlphaData используются как значения прозрачности; П 'direct' — в этом случае значения массива AlphaData выступают как индексы в текущей шкале прозрачности alphamap; П 'scaled' — в этом случае элементы массива AlphaData масштабируются от минимального до максимального значения свойства аьш текущих осей. Значение 'scaled' у AlphaDataMapping всех объектов устанавливается по умолчанию. Рис. 10.26. Сфера с изменяющейся по оси z прозрачностью Используя формат alpha (objectjnandle, значение), можно устанавливать параметры прозрачности для отдельного объекта. Но для этого можно воспользоваться и функцией set. Чтобы получить изображенную на рис. 10.26 сферу с плавно изменяющейся по оси z прозрачностью, достаточно выполнить следующие команды: » sphere » axis equal » h=findobj('Type','surface');
464 Глава 10 » a=get (h, ' ZData') ,- » set(h,'AlphaData',a,'FaceAlpha','interp') При работе со свойствами объектов существуют некоторые изменения. Во- первых, свойство AlphaData должно быть в нашем случае представлено матрицей размерности, совпадающей с ZData (XData и YData). Пользоваться значениями типа У нельзя, поэтому нам и пришлось считать значение ZData в отдельный массив. Во-вторых, появилось свойство FaceAlpha. Оно может принимать числовое значение от о до i, fiat, interp и texturemap. В случае числового значения (по умолчанию устанавливается 1) все грани объявляются непрозрачными (для 1), прозрачными (для о) или полупрозрачными со степенью прозрачности, пропорциональной значению. В случае fiat прозрачность для каждой грани является постоянной (определяемой массивом AlphaData), в случае interp прозрачность грани плавно изменяется (значения прозрачности также берутся из AlphaData). Для того чтобы использовать в качестве карты прозрачности объект типа image, надо задать свойство FaceAlpha равным texturemap. В случаях задания flat или interp возникает ограничение, что размерность AlphaData должна совпадать С размерностью XData, YData И ZData. Использование графического файла (или иным образом созданного объекта типа image) оправдано в тех случаях, когда требуется нарисовать изображение со сложными свойствами прозрачности.
Глава 11 Полиномы 11.1. Представление полиномов Полиномы от одной переменной имеют в MATLAB два разных представления — в виде вектора-строки из числовых коэффициентов и символьное, т. е. почти в "обычном" виде. Например, полиному -2хЗ+х-1 соответствуют: П вектор коэффициентов [-2 о i -1] или [-2,0,1,-1]; П символьное выражение -2*хЛ3+х-1. Для преобразования из одного формата представления полинома в другой (пример 11.1) используются функции poly2sym (для перехода от вектора коэффициентов к символьному представлению) и sym2poiy (для перехода от символьного представления к вектору коэффициентов). ^Пример 11.1. Преобразование представления полиномов - - -^.-1 » poly2sym<[-2 0 1-1]) ans = -2*хЛ3+х-1 » poly2sym([-2,0,l,-l]) ans = -2*х~3+х-1 » syms х; % объявление символьной переменной х » sym2poly{-2*x~3+x-l) ans = -2 0 1-1 Объявление символьной переменной, которое было сделано в предьщушем примере с помощью типа данных syms, допускает в одной строке перечисление нескольких имен, разделенных пробелами: » syms xl х2 хЗ » whos
466 Глава 11 Name xl x2 x3 Size lxl lxl lxl Bytes 1.28 128 128 Class sym object sym object syra object Другая возможность объявления переменной символьного типа предоставляется функцией sym. Как правило, имя символьной переменной и его запись в виде строки — аргумента функции sym — должны совпадать (пример 11.2). [Пример 11.2. Использование функции sym *■/' '* ■s**( t. ,,'~L'~ ^,:2 ,.. !i-..; » y=syrti('y') ; » whos Name Size Bytes Class у lxl 126 syra object Если к функции poly2sym обращаются только с числовым вектором коэффициентов, то она автоматически создает символьную переменную х и строит полином с ее использованием. Однако если к этой же функции обратиться с двумя входными аргументами, то полином будет построен относительно указанной переменной: ■>> syms у » poly2sym([-2 0 1 -1],у) ans = -2*у'Л3+у-1 Для каждого из двух способов представления полиномов имеется свой "ассортимент" операций. 11.2. Операции над полиномами, представленными вектором коэффициентов 11.2.1. Значение полинома Для вычисления значения полинома (пример П.3) применяется функция polyval, реализующая схему Горнера: y^polyval(p,x); Здесь: Пр- вектор коэффициентов, расположенных в порядке убывания степени х;
Полиномы 467 П х — значение аргумента; О у — значение полинома. Аргумент х может быть вектором или матрицей. Тогда значения полинома вычисляются отдельно для каждого компонента, а результат у будет иметь такую же размерность, как и аргумент х. (Пример 11.3. Вычисление значения полинома "-.. .„ , -rS... - ж » p=fl,-l]; » х=[1 2;3 4]; » yl=polyva.l (р, х) У1 - О 1 2 3 Независимой переменной в полиномах может быть не только скаляр, но и квадратная матрица. Тогда значением полинома является также квадратная матрица. Ее можно вычислить с помощью функции poiyvaim (пример 11.4). ; Пример 11А Вычисление полинома от матричного операнда - **'■• • I » р=[1,-1]; » х=[1 2;3 4]; » y2=polyvalm(p, х) О 2 .3 3 В этом примере полином имеет вид х-а, поэтому из матрицы х вычитается единичная матрица. 11.2.2. Сложение и вычитание Если степени полиномов совпадают, то совпадают и длины представляющих векторов. В этом случае можно просто сложить или вычесть эти векторы. В противном случае, когда степени полиномов различны, такой простой способ не годится — вначале надо выровнять длины представляющих векторов. Именно так работает функция poiysum, приведенная в [3]: function s = poiysum(p,q) % POLYSUM Сложение и вычитание двух полиномов
468 Глава 11 % С = polysum(A,B) вычисляет сумму С = А + В % С - polysum(A,-B) вычисляет разность С = А - В % length(С)=max(length(A), length(В)). % maxlen = max(length(pj, length(q)); pi = zeros(1, maxlen); ql = zeros(1, maxlen); pi (maxlen-length (p) +1 .-maxlen) = p; ql(maxlen-length(q)+l:maxlen) = q; s = pi + ql; 11.2.3. Умножение и деление Для выполнения этих операций используются функции conv (свертка) и deconvl с = conv (а, Ь); [q, г] =deconv (а, Ь) ; Вектор коэффициентов с — полином, являющийся произведением полиномов, представленных векторами коэффициентов а и ь. Векторы коэффициентов q и г — полиномы, являющиеся частным и остатком от деления полиномов, заданных векторами коэффициентов а и ь: a=conv(b,q)+r,- Для получения только частного к функции deconv можно обратиться с одним выходным аргументом: q=deconv(a,b); Проверьте школьным способом результаты работы фрагмента из примера 11.5. !:,.Прй'мер!11;'5; Умножение и деление:полиномов'Ъ&£$: g'-./ t&dUid-:*^#'-.->й~ » pl=[1,0,-2]; » р2=[2,1,-1,4); » plp2=conv(pl,p2) plp2 = 2 1-5 Z 2-8 » [d,r]=deconv(plp2,[1,-1])
Полиномы 469 d = 2 3-202 г = 0 0 0 0 0-6 11.2.4. Дифференцирование и интегрирование Для дифференцирования полипома, представленного вектором коэффициентов р, используется функция polyder: d=polyder(р); Функция возвращает вектор коэффициентов производной d. Если к — степень ПОЛИНОМа р, TO d(l)=k*p(l), d(2) = (k-l) *р(2> и т. д. Та же функция при обращении к ней с двумя входными аргументами — polyder (p,q) — находит либо производную от произведения полиномов (p*q), либо производную от дробно-рациональной функции (p/q)". d=polyder(р,q); % d - производная от p*q [c,d]=polyder(p,q]; % производная от p/q Значение производной от дробно-рациональной функции формируется также в виде дробно-рациональной функции c/d, где векторы с и d представляют полиномы — числитель и знаменатель производной. Приведем пример 11.6. ;^..,..„;р^.г.„„;..^т.7„.та.г...^ [;Примёр;1.1.6.Вь1Чйслен»1епроизводной:?' '^^S^flJ^ ... ЩШ^ ^■.:%$.г\ » р=[1 -1 0]; » q=tl 1']; » d=polyder(р, q) d = 3 0-1 » [a,b]=polyder(p,q) a = 12-1 b = 12 1 Следует отметить, что функция polyder: не отличается особым интеллектом. В том случае, когда числитель и знаменатель производной от p/q допускают сокращение, функция этого не делает (пример 11.7).
470 Глава 11 j Пример 11.7. Недостатки в работе функции poiyder , , „:| » р=[1,-1,0]; ». q=[l,0]; » [a,b)=polyder (р, q) а - 10 0 ь = 10 0 Очевидно, что х2/х2=1. Поэтому эквивалентный результат мог бы выражаться и более короткими векторами: a=[i],b=[i]. Для интегрирования полинома р применяется функция poiyint: q=polyint(р,с); Вторым аргументом в этой функции является константа интегрирования с (свободный член первообразной). Если в обращении аргумент с опушен, по умолчанию принимается с=о. Функция возвращает результат в виде вектора- полинома q. 11.2.5. Корни полинома Для вычисления всех корней полинома р используется функция roots: » r=roots(р) ; Функция roots возвращает вектор-столбец г, компонентами которого являются корни полинома р (пример 11.8). : Пример 11.8. Нахождение корней полинома » р=[1 2 2 0 0]; » roots(р) ans = Р О -1.0000 + l.OOOOi -1.0000 - l.OOOOi По известным корням xi, х2, ..., хп полинома степени п нетрудно восстановить коэффициенты приведенного полинома (коэффициент при старшей степени равен l): РЯ = (X-Xi) * (х-х2) * . . . " (х-хя)
Полиномы 471 Если вектор х представляет корни полинома, то восстановление вектора р его коэффициентов осуществляется с помощью функции poly: р= poly(х) ; С поиском корней полинома тесно связана задача интегрирования дробно- рациональной функции p/q, числитель и знаменатель которой являются полиномами степени п и m соответственно. Если n>m, из дроби p/q можно выделить частное — полином s степени n-m и "правильный" остаток r=pi/qi. В свою очередь, остаток г можно представить в виде суммы "простых" слагаемых вида zi/(x-xi) и (ui^x+vi) / (bi*x2+ci*x+di). Знаменатели этих дробей можно найти, зная корни полипома qi. В случае кратных корней вид указанного разложения несколько иной. Но так или иначе, вычисление интеграла от разложения, найденного таким способом, — задача на порядок более простая, чем интегрирование исходной функции. MATLAB предлагает функцию residue, которая помогает найти указанное разложение дробно-рациональной функции p/q: » [х,р,s]=residue{p,q); — Более подробную информацию о возможностях функции residue вы получите, набрав команду help residue. 11.3. Операции над полиномами, заданными в символьном виде 11.3.1. Значение полинома Для вычисления значения символьного полинома р используется функция subs (подстановка), которая подставляет на место независимой переменной заданное число или символьное выражение (пример 11.9). Пример 11:9; Вычисление значения символьного полинома _ .-=¾¾ ■» syms х a b % объявление символьных переменных » Р==хЛ2-х; % объявление полинома Р » subs(Р,2) % подстановка числа ans = 2 » subs(Р,a+b) % подстановка символьного выражения ans = (а+Ь)Л2-а-Ь 16 За к. 809
472 Глава 11 Если в записи полинома кроме независимой переменной используются другие символьные параметры, то функция subs разрешает замену и таких параметров, однако в этом случае нужно задавать три аргумента — имя полинома, имя замещаемого параметра и подставляемое выражение (пример НЛО). [; Пример 11 ;10.Вь1числе»ние полинома с символьными ^рэф^ициентами/'ЗР;^; » Q=a*x~2-x; » subs (Q, a,b+l) ans = (Ь+1)*хл2-х » subs[Q,x,1) ans = a-1 Если надо произвести подстановку сразу в несколько символьных параметров, то список замещаемых параметров задается в виде ячейки (т. е. в фигурных скобках) на месте второго аргумента и точно таким же способом на месте третьего аргумента задается список замещающих выражений (пример 11.11). [Пример 1Д;11. Подстановканескольких символьны^парщ^ров^'^^}^-^!!!''.»^ » subs(С,{х,а}, {3,1}) ans = 6 » subs(Q, (а,х), (Ы-1,2}) ans = 4*b+2 11.3.2. Сложение и вычитание Полиномы, представленные в аналитическом виде, можно складывать и вычитать, используя знаки обычных арифметических операций. В результирующем полиноме автоматически производится приведение подобных членов, имеющих однотипные коэффициенты (пример 11.12). [Пример 11.12: Сложение и вычитание полиномов ■ 1Ъ г- ;,,- а\с! >> syms х а » Р=хл2-х;
Полиномы 473 » 0=а*хл2-х; » R=x-1; » P+Q ans = х'л2-2*х+а*хл2 » P-R ans = хл2-2*х+1 » P+R ans = x"2-l 11.3.3. Умножение и деление Непосредственное использование операций * и / создает не полиномы, а выражения, представляющие собой произведение двух полиномов или дробь, числитель и знаменатель которой являются полиномами (пример 11.13). Не производится автоматически и сокращение дроби, когда числитель и знаменатель имеют общие множители. |. Примере.1.13..Умножение и деление полиномов Г ..„у, ' ^ :а^;.';г.Лй;-..л.^.Л?л.;^^<№й.;л..;.*&<.Л-.'::..-.: ;.. .'.i rn.i.. ■&:■.'..^.¾¾..^..¾¾.^.. :». . .'.; :.и'.Л5г. лч.'г. .:. ": -.г. Л -■.; » Р = хЛ2-х; » S=x; » P+S ans = (хл2-х)*х » P/S ans = (х'2-х)/х Для "нормализации" полученных выражений MATLAB предлагает две функции. Первая из них — simplify (упрощать). Хотя она и упрощает заданное выражение, не всегда возвращаемый ею. результат является полиномом: » simplify(P*S) ans= хЛ2*(х-1);
474 Глава 11 Функция simplify выполняет сокращение дроби, если числитель и знаменатель заданного выражения имеют одинаковый множитель. При этом может получиться как полином, так и более простое дробное выражение (пример 11.14). ; Пример 11.14. Упрощение полиномов ■•= ■■ '• ,!*Л 4^ "J"'^! » simplify(P/S) ans = х-1 » 0=хЛ2+х; »P/Q » ans= (х^2-х)/(хЛ2+х); » sirrplify(P/Q) ans = г (х-1)/(а*х-1) Вторая функция — expand (раскрывать формулу). Она раскрывает скобки и в случае произведения полиномов возвращает также полином (пример 11.15). » expand(P*S) ans= хЛ3-хЛ2; 11.3.4. Дифференцирование и интегрирование Для дифференцирования символьного полинома р используется функция diff (пример 11.J6). ."■■"•■■ r-«:-v7:-T^" ;-™^?г"";™ " ^Т":"Г^"Т^"^^^'Щ^^"'ЩШШ^Щ^ ; Пример 11.16. Дифференцирование символьного полинома ^. " ' я* -.iV't'J » Р=хЛ3-2*хЛ2+5*х-3; » diff (Р) ans = 3*хл2-4*х+5
Полиномы 475 Обращение к этой функции со вторым аргументам к позволяет найти к-ю производную: » diff (Р, 2) ans = б*х-<3 » diff(Р,3) ans = 6 Коэффициенты полинома могут зависеть от одного или нескольких параметров. Функция diff допускает не только дифференцирование по любому такому параметру, но и находит k-ю производную по указанному параметру (пример 11.17). [Пример 11.17. Поиск производной по символьному параметру. "•*» ^¾^\р§, ■;?,' "$\ » syms х в » К=хЛ3-2*а*хЛ2+5*х-3; » diff(R,а) % первая произведшая по а ans = -2*хл2 » diff(R,а,2) % вторая производная no а ans = О Неопределенный интеграл от символьного полинома вычисляется с помощью функции int, допускающей несколько вариантов обращения. В простейшем случае у нее единственный аргумент — подынтегральное выражение (пример 11.18). I Пример 11.18. Интегрирование символьного полинома ■■■■':. * :,. й-»ай » Р=хЛ3-'2*хЛ2+1; » iiit(P) ans = 1/4*хл4-2/3*хлЗ+х _il
476 Глава 11 Добавление двух дополнительных аргументов в функции int позволяет вычислять определенные интегралы с заданными пределами: » int(E,0,2) % интеграл от 0 до 2 ahs = 2/3 Пределы интегрирования могут быть не только числовыми значениями, но и символьными выражениями: » int[P,a,a+2) ans = 1/4*(а+2)Л4-1/4*аЛ4-2/3*(а+2)А3+2/3*а*3+2 11.3.5. Корни и разложение полинома на множители Для нахождения корней полинома, представленного в символьном формате, необходимо обратиться к функции solve, аргументом которой может быть имя полинома, строка с аналогичным выражением или явная запись формулы полинома (пример 11.19). ; Пример 11.19. Поиск корней символьного полинома ?"•.■ «-' -¾¾.. ;,. >;.*<;,,:- ,,v.,,..-M\-rifl » syms х » Р = х~3+9*х-26; » s = solve(Р); » si = solve(хл3+9*х-26) ; » s2 = боЬлэ('хлЗ+9*х-26'); Все три обращения дают идентичный результат — вектор-столбец, компонентами которого являются корни полинома: » S S = [ 2) [ -l+2*i*3~(l/2)] [ -l-2*i*3"(1/2)] С помощью функции solve можно получить, например, известную формулу для корней квадратного уравнения (пример 11.20).
Полиномы 477 '■■'и''""-"'-'""'' 'л м — — '"'"* - ■'i--, . ■ "■ ."■ " „ V? -'- 1. ""'■"- Yf'"" .*" i ■* -. . " ".Чьим" ,J>'SV.'A ;"ca-jri '- " .* *" ""- цПример .11.20..Формула для ;корнеи квадратного уравнения ~л> ^р ^:'i » syms х a b с » s=solve(a*x"2+b*x+c) s = [ 1/2/а*(-Ь+(ЬЛ2-4*а*с)Л(1/2))] [ 1/2/а*(-Ь-(Ьл2-4*а*с)л(1/2>)] Примерно так же можно получить аналитические выражения для корней полиномов третьей и четвертой степеней. Правда длина таких выражений может достигать 300—400 символов, так что проще искать корни полиномов, представленных векторами коэффициентов. Для полиномов выше четвертой степени в общем случае решения в радикалах не существует, и система MATLAB с этим фактом знакома: » solve(хЛ5+х-а) , ??? Error using ==> solve Error, (in allvalues/rootseq) cannot evaluate with symbolic coefficients С помощью функции factor (P) можно разложить полином р на сомножители (пример 11.21). ^Пример 11.21, Разложение на множители""-"-" '* " 'ьл.' "j-'V .-г^&Г i "''-"'^Ч *{ » Р=хЛ2-х; » factor(Р) ans = х*(х-1) » Q=x"2-rx; » factor(P*Q) ans = (х-1)*хл2*(х+1) Если аргументом функции factor является дробь вида p/q, то числитель р и знаменатель q раскладываются независимо друг от друга, после чего обшие делители сокращаются (пример 11.22). [Лритр'^^.Разложэииенамножит^л.и.дроб^...^ -.; -";?^\ _!*, » factor(P/Q) ans = (х-1)/(х+1)
) Глава 12 Линейная алгебра Основным типом данных в MATLAB являются матрицы. Вектор-строка, вектор-столбец и даже скаляр рассматриваются как частные случаи матриц. Для матриц определены не только стандартные операции, изучаемые в курсе линейной алгебры, но и ряд дополнительных. В связи с тем, что в материале этой и последующих глав интенсивно используются матричные операции, напомним вкратце некоторые детали. 12.1. Основные матричные операции В табл. 12.1 приведена информация о стандартных операциях, в которых матричные операнды обозначены через х и у, а скалярный операнд — через п. Таблица 12.1 Формат Пояснения операции X+Y Сложение матриц. Операнды и результат имеют одинаковые размеры х+n или п+х Прибавление скаляра к каждому элементу матрицы x-Y Вычитание матриц. Операнды и результат имеют одинаковые размеры х-n или n-Х Вычитание скаляра из каждого элемента матрицы или вычитание каждого элемента матрицы из скаляра X*Y Умножение матриц. Если размерность X равна pxq, а размерность Y равна qxr, то размерность результата — рхг х*п или п*х Умножение каждого элемента матрицы на скаляр X' Транспонирование матрицы. Для вещественных матриц строки становятся столбцами, а столбцы — строками. Для комплексных матриц после этого все элементы заменяются комплексно- сопряженными числами
480 Глава 12 Таблица 12.1 (окончание) Формат Пояснения операции X. ' Транспонирование матрицы. Комплексные матрицы транспонируются без изменения их элементов inv (X) Обращение квадратной матрицы (вычисление х"!) x\Y Левое деление матриц — аналог операции X_1*Y X/Y Правое деление матриц — аналог операции x*Y_1 хлп Возведение квадратной матрицы в степень. Если п — целое, то это эквивалентно умножению х*Х*... *х (п сомножителей). Для вещественных или комплексных значений п степень вычисляется как функция от матрицы с использованием собственных чисел и собственных векторов. Результат операции — квадратная матрица плх Возведение скаляра в матричную степень (х — квадратная матрица). Результат вычисляется как функция от х с использованием собственных чисел и собственных векторов. Результат операции — квадратная матрица kron (X, Y) Произведение Кронекера (тензорное произведение) X®Y. Каждый элемент Xij матрицы х заменяется блоком xtj*Y. Таким образом, элементами матрицы-результата являются всевозможные произведения элементов матриц-сомножителей MATLAB поддерживает операции покомпонентного умножения (x.*y, п.*у или х.*п), деления (x./y, п./y, x./n, x.\y, n.\Y или х.\п) и возведения в степень (х.Лу, п.лу или х.Лп). В отличие от обычных матричных операций в этом случае перед знаком операции ставится точка. Любой из операндов может быть скаляром. В противном случае матрицы-операнды должны иметь одинаковые размеры. Таковы же размеры и матрицы-результата. В табл. 12.2 приведены сведения о функциях, вычисляющих наиболее употребительные характеристики матриц и векторов. Таблица 12.2 Формат Пояснения вызова det (X) Определитель или детерминант квадратной матрицы rank (X) Ранг матрицы — число линейно независимых строк (столбцов). Ранг равен наибольшему порядку-ненулевого определителя (минора), полученного вычеркиванием части строк и столбцов
Линейная алгебра 481 Таблица 12.2 (окончание) Формат Пояснения вызова trace (X) След матрицы — сумма значений элементов, расположенных на главной диагонали norm (V) Евклидова норма вектора — корень квадратный из суммы квадратов компонентов norm(X) Сингулярная норма матрицы: наибольшее сингулярное число (см. разд. 12.7.6); совпадаете максимальным отношением norm (X*V) к norm (V) для ненулевого вектора v norm(X, 'fro') Норма Фробениуса — квадратный корень из trace (Х'*Х) size (х.) Размер матрицы — вектор из двух компонентов, первый из которых равен числу строк X, а второй — числу столбцов Вычисление ранга — довольно деликатная операция, она выполняется с помощью сингулярного разложения матрицы (см. разд. 12.7.6). Ранг определяется как количество сингулярных чисел si > s2 > ..., не являющихся пренебрежимо малыми. Чтобы сделать определение ранга управляемым, следует пользоваться модификацией функции rar.k(x, toi), где второй параметр задает порог — сингулярные числа, меньшие его (они все неотрицательны), считаются нулями. По умолчанию функция rank (X) использует tol=max(size(X))*norm(X)*eps где eps — установленная точность вычислений (по умолчанию eps= =2.220<3е-01б). 12.2. Скалярное и векторное произведение Скалярное произведение геометрических векторов а и ь (т. е. направленных отрезков на плоскости или в пространстве) равно произведению модулей (длин) этих векторов на косинус угла <р между векторами, приведенными к общему началу: (a,b) = |a|*|b|*cos(p В декартовой системе координат скалярное произведение вычисляется как сумма произведений соответствующих компонентов обоих векторов: (a,b)=a(l)*b(l)+a(2)*b(2) (a,b)=a(l)*b(l)+a(2)*b(2)+a(3)*b{3) (a,b)=a(l)*b(l)+a(2)*b(2)+...+a(n)*b(n>
482 Глава 12 Количество слагаемых равно размерности пространства. Один из способов вычисления скалярного произведения заключается в использовании функции dot (пример 12.1). ^Пример: 1¾¾ Вычисление скапя » а=[1 -1 2]; » Ь=[2 4 1]; » c=dot{a,b) с = О Функция dot одинаково хорошо работает и в тех случаях, когда оба вектора представлены в виде столбцов или когда один вектор является строкой, а другой — столбцом: » c=dot(a',b') с = О » c=dot(a,b') с = О >> c=dot(a',b) с = .0 Вторым способом вычисления скалярного произведения является использование функции sum (пример 12.2). ^Пр;имер^2.2;.ВМ1чИсл^ние скалярного произведения спонощью функции sum У » и=-0.5:0.5:2 .и = -0.5000 О » v=2:-0.5:-0.5 v = 2.0008 1.5000 » sum(u.*v) ans = -1 0.5000 1.0000 1.5000 2.0000 1.0000 0.5000 0 -0.5000
Линейная алгебра 483 Скалярное произведение векторов тесно связано с вычислением нормы вектора: для любого а имеет место равенство dot(a,a)=norm(a)Л2 С помощью этих функций можно найти косинус угла между векторами: cos_ab=dot(a,b)/(norm(a)*norm(b)) Буквальный геометрический смысл эта формула имеет в пространствах R2 и R3, однако ее применяют и для векторов произвольной размерности, рассматривая эту формулу как определение (пример 12.3). ; Пример 12.3. Поиск косинуса угла между векторами 1 **ЩЦ$Щ^''" ''"*■ :<; "Л*"*Ц » cos_uv=dot(u,v)/(norm(и)*norm(v)) cos_uv = -0.1290 Для рассматривавшихся выше векторов а и ь имеем cos_ab=0, т. е. эти векторы взаимно перпендикулярны. Рассмотрим два других вектора, первый из которых идет по биссектрисе между осями х и у. » al=[l 1 0]; а второй — по биссектрисе между осями yuz. » Ы=[0 1 1]; Для них косинус угла » cosl=dot(:al,bl> / (norm(al) *norm(bl)) cosl = 0.5000 Теперь можно найти угол между векторами al и ы (в радианах): » anglel=acos(cosl) aiiglel = 1.0472 и перевести его в градусы: » anglel_deg=anglel*180/pi anglel_deg = 60.0000 Скалярное произведение векторов с комплексными компонентами, вычисляемое функцией dot, представляет собой сумму произведений компонентов
484 Глава 12 первого сомножителя на числа, комплексно сопряженные к соответствующим компонентам второго сомножителя (пример 12.4): (а,Ь)=а(1)*Ь'(1)+а(2)*Ь'(2)+...+a(n)*b'(п) ^Пример 12.4, Скалярное произведение векторое с комплексными^! ^¾¾¾^ ^компонентами. ^¾ .¾. t .• ,' ' -,.. ..,,'. " ЛЬ\',' ''+Щ, i » p=[l+i -1 2-i]; » q=[2-i 2 1+i]; » r=dot (p, q) r = 0 Векторное произведение определено лишь для векторов в трехмерном пространстве. Для векторов а и ь их векторное произведение v=axb удовлетворяет следующим условиям: П |v| = |a|* |b|*sin(p, где ф— угол между векторами, отложенными от одной точки (| v | равен площади параллелограмма, построенного на векторах а и ь); П вектор v перпендикулярен векторам а и ь; П тройка векторов <a,b,v> ориентирована так же, как и координатные оси <х,у, z>. В декартовой системе координат векторное произведение v=axb выражается формулами: v(l)=a(2)*b(3)-a(3)*b(2) v(2)=a(3j*b(l)-a(l)*b{3> v(3)=a(l)*b(2>-a(2)*b(l) В MATLAB для вычисления векторного произведения используется функция cross (пример 12.5). ^"■щ^гщ^угу^т^у:;^^^' ™ " ■'■■'•^•■"™";ш"^^раа^^ |;Прийёр;12.5;-Вычисление векторного произведения j,s|||J^ .^-, _ ' Jjp'v "' » a=[l -1 21; » b=[2 4 1]; » v=cross (a,b.) v = -9 3 6
Линейная алгебра 485 Если один из векторов представлен в виде строки, а другой в виде столбца, функция cross вычисляет строку: » v=cross(a,fa') v = -9 3 6 » v=cross(а',Ь) v = -9 3 6 Если оба вектора представлены в виде столбцов, функция cross также вычисляет столбец: » v=cross(a',b') v = -9 3 б Как сказано выше, норма векторного произведения равна площади параллелограмма, построенного на векторах-сомножителях: » S=norm(v) S = 11.2250 Если компоненты векторов являются комплексными числами, функция cross вычисляет результат по тем же формулам, однако векторное умножение комплексных векторов не представляет интереса. Довольно деликатной задачей является вычисление ориентированного угла между векторами на координатной плоскости ху (пример 12.6). {Пример 12.6. вычисление ориентированногр угла между векторами у .^ Л. ^. j » а=[-3 3] ; » Ь=[ 6 3]; » cos_ab=dot(a,b)I(norm(a)*norm(b)) cos_ab = -0.3162 Ясно, что угол тупой, но какого знака? Чтобы узнать это, дополним векторы до трехмерных, задав третью координату, равную о: » аЗ=[а 0] аЗ = -3 3 0
486 Глава 12 » ЬЗ=[Ь 0] ьз = .6 3 0 Теперь можно найти векторное произведение: » v=cross(аЗ,ЬЗ) v = О 0 -27 Единственная отличная от нуля координата этого вектора равна произведению норм векторов аЗ и ьз и синуса угла между ними. Поэтому: » sin_ab=v(3)/(norm(a3)*гюгт(ЬЗ)) sin_ab = -0.9487 Знак свидетельствует, что этот угол отрицателен, т. е. поворот отакь происходит в отрицательном направлении (по часовой стрелке, если система координат правая). Значение этого угла в радианах можно найти с помощью функции atan.2: » alpha=atan2(sin_ab,cos_ab) alpha = -1.8925 Переведя этот угол в градусы, получим: » a.lpha_deg=a.lpha*180/pi alpha_deg = -108.4349 Еще одна геометрическая задача, связанная с нахождением объема параллелепипеда, построенного на векторах а, ь и с, решается с помощью смешанного произведения векторов, определяемого как скалярное произведение вектора а на векторное произведение ь*с: v=a-(b*c) Собственно объем параллелепипеда равен модулю смешанного произведения (пример 12.7), и вычислить его можно по одной из формул: | v | = abs (dot (a, cross (b,c) ) ) | v | = abs (sum (a. 'cross (b, c) ) ) j Пример 12.7. Вычисление объема параллелепипеда » а = [4,0,0]; » b = [0,6,0.]; » с = [0,0,1];
Линейная алгебра 487 » abs (dot (a, cross (b, с))) ans = 24 12.3. Стандартные матрицы, фрагменты и блоки Довольно часто в линейной алгебре используются единичные матрицы (элементы главной диагонали равны 1, а все остальные — о), нулевые матрицы (все элементы равны о), матрицы, все элементы которых равны ненулевой константе (обычно i). Список функций, предлагаемый в MATLAB для формирования таких матриц, приведен в табл. 12.3. Таблица 12.3 Формат вызова Возвращаемое значение еУе <п) Единичная матрица размерности пхп eye (m, п) Единичная матрица размерности mxn zeros (п) Нулевая матрица размерности пхп zeros (га, п) Нулевая матрица размерности mxn ones (п) Матрица размерности пХп, заполненная единицами ones (in, п) Матрица размерности mxn, заполненная единицами Для выделения элементов матрицы используются индексы, заключенные в круглые скобки— x(i,j), где i определяет номер строки, a j — номер столбца. Отсчет индексов ведется от 1. Можно использовать групповое выделение элементов матриц с помощью обозначений, характерных для операторов цикла,— beg:step:end (здесь beg— начальное значение индекса, step — приращение, end — конечное значение индекса). Отсутствие начального значения воспринимается как отсчет от 1, отсутствие шага соответствует единичному приращению, отсутствие конечного значения воспринимается как максимальный индекс. В табл. 12.4 приведены наиболее характерные выделения. Таблица 12.4 Формат выражения Пояснение X (i, :) i-я строка матрицы х X (il: i2, :) Строки матрицы X, начиная с 11 по х2 х (il:h: i2, :) Строки матрицы х, начиная с il по i2 с шагом h
488 Глава 12 Таблица 12.4 (окончание) Формат выражения Пояснение X (:, j ) j -й столбец матрицы X X (:, j 1: j 2) Столбцы матрицы X, начиная с j 1 по j 2 X(:,jl:h:j2) Столбцы матрицы X, начиная с j 1 по j 2 с шагом h X(il:i2,jl:j2) Подматрица, ограниченная строками с il по 12 и столбцами с j 1 по j2. Возможно задание шага по любому измерению tr i 1 (X) Верхний треугольник матрицы х (включая главную диагональ) t г i и (X) Нижний треугольник матрицы х (включая главную диагональ) diag (X) Вектор-столбец, образованный элементами главной диагонали матрицы х diag (v) Квадратная матрица порядка length (v), главная диагональ которой есть вектор v diag (v, k) , k>0 Квадратная матрица порядка length (v) +k, k-я наддиаго- наль которой есть вектор v diag[v,k), k<0 Квадратная матрица порядка length (v)+abs (k), I k|-я поддиагональ которой есть вектор v [XI Х2 . .. ] или Горизонтальный блок, который представляет собой вектор- [XI, Х2, ... ] строку из матриц xi, Х2,... Все матрицы должны иметь одинаковое число строк [XI; Х2; . .. ] Вертикальный блок, который представляет собой вектор- столбец из матриц xi, Х2,... Все матрицы должны иметь одинаковое число столбцов blkdiag Блочно-диагональная матрица с блоками XI, Х2, ... (XI,Х2,...) 12.4. Простые преобразования матриц В табл. 12.5 приведены преобразования матриц, включенные в библиотеку MATLAB. Таблица 12.5 Формат вызова Выполняемая операция xot90 (X) Матрица х поворачивается на 90°против часовой стрелки rot90 (X, к) Матрица X поворачивается к раз
Линейная алгебра 489 Таблица 12.5 (окончание) Формат вызова Выполняемая операция flipud (X) Столбцы матрицы х переворачиваются "вверх ногами" f liplr (X) Строки матрицы х переворачиваются "задом наперед" f lipdim(X, dim) Переворот относительно размерности с номером dim flipdim(X,l) Тоже, что flipud (X) (переставляются строки) f lipdim(X, 2) То же, что f liplr (X) (переставляются столбцы) reshape (X, m, п) Создает mxn-матрицу, заполненную элементами X. Заполнение происходит по столбцам. Если X — матрица, ее элементы выбираются также по столбцам. Если число элементов X не совпадает с произведением m*n, выдается сообщение об ошибке В примере 12.8 приведены несколько вариантов использования указанных функций. SS-'V...-." "■ ■""" '■-"i-VVrs™ •"""Г; ■■•-■у"-: -г--- -*™sw ) ■•; - _, [Пример 1?8. Преобразования матриц (| . v«: .'. Л .^-.¾... '-' » А = [12 3; 4 5 6] А = 12 3 4 5 6 » ro.t90(A) ans = 3 6 2 5 1 4 » flipud (А) ans = 4 5 6 12 3 » f liplr (А) ■ans = 3 2 1 6 5 4 » В = reshape(A,3,2) В = 1 5 4 3 2 6
490 Глава 12 12.5. Некоторые классы матриц 12.5.1. Симметричные и кососимметричные матрицы Квадратные матрицы, у которых Aij = Ац, называются симметричными. Квадратные матрицы, у которых а15 = -а,ь называются кососимметричньши. Диагональные элементы кососимметричной матрицы равны нулю. 12.5.2. Эрмитовы и косоэрмитовы матрицы Квадратные матрицы, у которых Ai:j = а3д , называются эрмитовыми или самосопряженными. Черта сверху означает здесь комплексное сопряжение. Для эрмитовой матрицы а = а'. Диагональные элементы эрмитовой матрицы вещественны. Квадратные матрицы, у которых А:3 = -ADiI называются косоэрмитовыми. Для косоэрмитовой матрицы А = -А'. Мнимые части диагональных элементов косоэрмитовой матрицы равны нулю. 12.5.3. Ортогональные (унитарные) матрицы Квадратные матрицы, у которых а"1 = А', в вещественном случае называются ортогональными, а в комплексном — унитарными. 12.6. Специальные матрицы 12.6.1. Матрица Гильберта и обратная к ней Матрицей Гильберта называют квадратную матрицу с элементами i/(i+j-i). Она является знаменитым примером плохо обусловленной матрицы. Матрица Гильберта создается функцией hilb(n). Определители матриц Гильберта очень быстро убывают с ростом п. Матрица, обратная к матрице Гильберта, целомисленна, для ее точного построения можно воспользоваться функцией invhiib(n) — пример 12.9. | Пример 12.9. Матрица Гильберта ,; ■ - -&*" iiw ~'Т'х » H=hi.lb(5) 5ПЗ = 1.0000 0. 50.00 0.3333 0.250.0 .0.2000
Линейная алгебра 491 0.5000 0.3333 0.2500 0.2000 0.3333 0.2500 0.2000 0.1667 0.2500 0.2000 0.1667 0.1429 0.2000 0.1667 0.1429 0.1250 » det(H) ans = 3.7493G-012 » Hinv=invhilb(5) Hinv = 25 -300 1050 -1400 630 » det(Hinv) -300 4800 -18900> 26880 -12600 1050 -18900 79380 -117600 56700 2.6672e+011 12.6.2. Матрица Адамара Матрицей Адамара называется квадратная матрица н порядка п с элементами 1 или -1, такая, что н'*н=п*еуе(п). Это означает, что строки матрицы Адамара попарно ортогональны. Матрица Адамара порождается функцией hadamard(n) — пример 12.10. Матрица Адамара порядка п существует только при п, кратных 4. Кроме того, п, п/12 или п/20 должно быть степенью 2. Гпример;1рр!-№^ » hadamard(4) ar.s = 1111 1-1 1-1 1 1-1-1 1-1-1 1 12.6.3. Матрица Паскаля Матрицей Паскаля называется симметричная положительно определенная матрица порядка п, сформированная из биномиальных коэффициентов. Матрица Паскаля порождается функцией pascal(п) — пример 12.11. 0.1667 0.1429 0.1250 0.1111 -1400 26880 117600 179200 -88200 630 -12600 56700 -88200 44100
492 Глава 12 [^мер 12.1.1. rj^^m^A J"^... -Й^^Й^^ШЁ J » pascal(4) ans = 1111 12 3 4 1 3 6 10 1 - 4 10 20 12.6.4. Матрица Теплица Каждый элемент матрицы Теплица t,, зависит только от разности индексов (i-j). Вследствие этого: tji = tjj - t.33 = - - - ti2 = ta.> = t« = -. . t21 = tj? = t«" — ... Таким образом, теплицева матрица полностью определяется заданием первого столбца и первой строки, причем первые компоненты этих двух векторов должны совпадать. Матрица Теплица (пример 12.12) создается функцией toepiitz (c,R). где с— заданный (первый) столбец, R— заданная (первая) строка. Более простая команда toepiitz (К) создает симметричную (в комплексном случае — эрмитову) матрицу Теплица с первой строкой r. ; ■■"■ v ■; ■ к- ■} I Пример 12.12. Матрица Теплица ...:"' ' ' 1¾).^^^^^¾^^¾¾^.^%¾.¾ » С = [0; 1; 2; 33; » R = [0 -1 -2] ; » toepiitz(С,R) ans = 0 -1 -2 10-1 2 1 0 3 2 1 12.6.5. Матрица Ганкеля Каждый элемент матрицы Ганкеля ru3 зависит только от суммы индексов (i+j). Вследствие этого:
Линейная алгебра 493 Таким образом, матрица Ганкеля полностью определяется заданием первого столбца и последней строки, причем общие компоненты этих двух векторов должны совпадать. Она формируется с помощью функции hankei(c,R), где с — заданный (первый) столбец, r — заданная (последняя) строка. Более простая функция hankei(C) создает симметричную матрицу Ганкеля с первым столбцом с, причем все элементы ниже вспомогательной диагонали (сумма индексов i+j > n+i) равны нулю (пример 12.13). •'' »"■-—! ..,.-...-.....-.--.-...-.. „...„..„.,,....,.,..„..... „......,,,.......„.....,.,...............,.,,.,.,.,...,.. :■ я^д^; тадаиидявк |}Пример. 12^.3. Матрица^анк^от '^Щ^^ф^ ^^-^у, Щ, > '--^Т: » С = » R = [0; [3 1; -2 - » hankel (С, К] ans = 0 1 2 3 1 2 3 -2 » hankel(С) ans = 0 1 2 3 1 2 3 0 2; -4] 3]; ; 2 3 -2 -4 2 3 0 0 3 0 0 0 Матрица Гильберта одновременно является и ганкелевой, тогда как обратная к ней матрица ганкелевой не является. 12.6.6. Матрица Вандермонда Элементы матрицы Вандермонда удовлетворяют следующим условиям: П Vi^tCi)11"1, где с — предпоследний столбец матрицы v; О Vi,n=l- Матрица Вандермонда создается функцией vender (О — пример 12.14. | Пример 12:14. Матрица Вандермонда •■•' ™ ■' ""'Ш> ^"/'." •-,*'" » С = [2; 3; 51; » vander(С)
494 Глава 12 ans = 4 2 1 9 3 1 25 5 1 12.6.7. Магический квадрат Магическим квадратом называется квадратная матрица порядка п, заполненная числами 1, 2, ..., nz таким образом, что суммы чисел в каждой строке, в каждом столбце и в обеих диагоналях одинаковы и равны nx(n2+i) /2. Магические квадраты существуют при всех п>2. Простые преобразования (транспонирование, переворачивание строк и столбцов, поворот) сохраняют свойство матрицы быть магическим квадратом. Магический квадрат порядка п (один из многих возможных) создается функцией magic (п) —пример 12.15. ! Пример 12.15. Магический квадрат'''^'- О'- ^к-"-^;"й-? » magic (3) ans = 8 16 3 5 7 4. 9 2 » magic (4) ans = 16 2 3 13 5 11 10 8 9 7 6 12 й 14 15 1 12.7. Разложение матриц Разложением матрицы называется ее представление в виде суммы или произведения нескольких (чаще всего двух) матриц определенного вида. 12.7.1. Разложение Эрмита Любую квадратную комплексную матрицу можно представить в виде А = Hi+I*H2
Линейная алгебра 495 где матрицы Hi и н2 — эрмитовы (пример 12.16). Они определяются однозначно и могут быть найдены.с помощью формул Hi = (А+А')/2 Н, = (A-A')/(2i) Напомним, что А' — матрица, полученная из а транспонированием с последующей заменой всех элементов комплексно-сопряженными числами. : .Пример ;Щ6^^лсшени^Зр|^^>^ ,,ti » А=[3 -3-i; 1 0] А = 3..0000 -3.0000 - 1.00001 1.0000 о » Н1={А+А')/2 HI = 3.0000 -1.0000 - 0.5000i -1.0000 + 0.5000i 0 » Н2=(А-А')/(2i) Н2 = 0 -0.5000 + 2.0000i -0.5000 - 2.00001 0 » B=Hl+i*H2 В = .3.0000 -3.0000 - l.OOOOi 1.0000 о Эрмитово разложение позволяет оценить собственные числа матрицы: по теореме Бендиксона вещественные части собственных чисел матрицы А заключены между наименьшим и наибольшим собственными числами матрицы нь а мнимые части собственных чисел матрицы а заключены между наименьшим и наибольшим собственными числами матрицы н2 (напомним, что собственные числа эрмитовых матриц вещественны). В приведенном выше примере: П собственные числа матрицы А равны 2±i; О собственные числа матрицы hi равны -0.3708 и З.з70в; О собственные числа матрицы н2 равны ±2.0616. Любую квадратную вещественную матрицу можно представить в виде A = S+K
496 Глава 12 где матрица s — симметричная, а к — кососиммётричная. Они определяются однозначно и могут быть найдены с помощью формул: S = <А+А')/2 К = (А-А*)/2 iПример 12l 1?. Разложение квадратной •матрицыУ&С^Дт"--'' ^¾¾¾¾ "■ ■ ,1 » A=[4 -1 -2; 2 1 -2; 1-11] A = 4 -1 -2 2 1-2 1-11 » S=(A+A')/2 S = 4.0000 0.5000 0.5000 1.0000 -0.5000 -1.5000 » K=(A-A')/2 К = 0 -1.5000 1.5000 0 1.5000 0.5000 » B=S+K В = 4 -1 -2 2. 1 -2 1-11 12.7.2. Скелетное разложение Пусть а — матрица размерности mxn ранга г. Ее можно представить в виде произведения А = В*С где в — матрица размерности mxr, ас — матрица размерности гхп. Сомножители скелетного разложения определяются неоднозначно (пример 12.18). В качестве в можно взять любой базис пространства столбцов матрицы а, тогда столбцы матрицы с состоят из коэффициентов разложений столбцов матрицы а по столбцам матрицы в. -0.5000 -1.5000 1.0000 -1.5000 -0.5000 0
Линейная алгебра 497 Можно предложить два варианта построения матрицы в: □ применить функцию [R,jb] = rref(A) которая вырабатывает R-ступенчатую форму матрицы а и jfc — строку, содержащую номера столбцов матрицы а, образующих базис. Матрицу в можно получить, выделив эти столбцы: В = A(:,jb) □ применить функцию В = orth(A) В этом случае столбцы матрицы в представляют собой ортонормирован- ный базис пространства столбцов матрицы А. Произведение в'*в в этом случае дает единичную матрицу (eye (г)). При любом варианте построения матрицы в второй сомножитель с ищется с помощью левого матричного деления: С=В\А ■К'-Чй^да "srv".^":vp 4-'-v •- ;"\i: '.■ ;-ч- ywfwe^vw»^"^^-»».; I,Пример 12.18. Скелетное разложение . т" .-!- - :" ' -'-'•- "■'-. » A = [4 2 2; 2 2 0; 2 0 2] А = 4 2 2 2 2 0 2 0 2 » [R,jb] = rref(A) R = 10 1 0 1-1 0 0 0 jb = 1 2 » В = A(:,jb) В = 4 2 2 2 2 0 » С = В\А С = 1.0000 0.0000 1.0000 -0.0000 1.0000 -1.00.00
498 Глава 12 » D = В*С D = 4.0000 2.0000 2.0000 2.0000 2.0000 0.0000 2.0000 0.0000 2.0000 i 12.7.3. LU-разложение При выполнении прямого хода преобразований строк матрицы а по методу Гаусса матрица приводится к верхнему треугольному виду и (все числа под диагональю равны нулю). Если при этом не делаются перестановки строк, то матрица, умножение на которую слева равносильно сделанным преобразованиям строк, оказывается нижней треугольной l (все числа над диагональю равны нулю). В результате получаем так называемое LU-разложеиие матрицы (пример 12.19): А = L*U Обозначения матриц L и и происходят от английских слов lower (нижний) и upper (верхний). Если при выполнении прямого хода преобразований строки матрицы не делятся на ведущие элементы, то все числа на диагонали матрицы L равны 1. Подставив это разложение в систему уравнений Ах=ь, получим LUx=b. Обозначим их=у, тогда Ly=b. Таким образом, решение системы уравнений Ах=ь с квадратной матрицей свелось к последовательному решению двух систем с треугольными матрицами (сначала ъу=ь, потом их=у). Требование "не переставлять строки матрицы" противоречит общепринятому способу выбора ведущего элемента (берется максимальный по модулю элемент в столбце), поэтому реально (т. е. с учетом перестановки строк) матрица l получается не треугольной, но приводится к треугольной обратной перестановкой строк. Такой результат получается, если воспользоваться функцией lu в формате [L,U]=lu(A). I Пример 12.19, LU-разложение . ;,-,., » А = [1 л 1 3; 0-13 -1; 3 10 2; 1-251] А = 14 13 0-1 3-1 3 10 2 1-251 » [L,U]=lu(A>
Линейная алгебра 499 L = 0 1 0 3 3333 0 0000 3333 0000 0 0 0 1.0000 -0.2727 0 -0.6364 1.0000 3.6667 0 0 0 1 1 5 0 5806 0 0000 0 0000 6364 0 0 1.0000 0 0 2.0000 2.3333 1.8182 -1.4194 Есть возможность получить "истинно треугольное разложение", а также матрицу перестановки строк, которая к такому виду приводит (пример 12.20). Для этого надо выполнить команду [l,u,p]=1u{A), которая кроме нижней треугольной матрицы l и верхней треугольной матрицы и порождает матрицу перестановки р. Между матрицами — участниками этой команды имеет место соотношение p*a=l*u. Для сведения системы уравнений с квадратной матрицей к двум системам с треугольными матрицами надо ах=ь умножить слева на матрицу р — в результате получится рах=рь. После этого следует заменить в левой части ра на ьи — система распадется на две системы с треугольными матрицами Ly=Pb и их=у (предварительно надо найти переставленные правые части рь). >Пример 12.20, Треугольное разложение Ж » [L,U,F] = L = 1.0000 0.3333 0.3333 0 и = '3.0000 0 0 0 р = 0 1 0 0 =1и (А) 0 0 0 1 0 1.0000 -0.6364 -0.2727 1.0000 3.-6667 0 0 1 0 0 0 1 0 1 5 0 0 1 0 0 0 0000 5806 0 0000 6364 б 0 0 0 1.0000 2.0000 2.3333 1.8182 -1.4194
500 Глава 12 12.7.4. Разложение Холецкого Это вариант LU-разложения для симметричной положительно определенной матрицы. Такую матрицу можно представить в виде A = R'*R где r — верхняя, а к' — нижняя треугольные матрицы. Разложение Холецкого (пример 12.21) получается с помощью команды R=chol(А). |Прймёр^1;2^ Л-4 -¾1-^ v -": Т •' ;.!л&*?! у*&- *' &W..' '■';"""-J ». А=[5 4 2; 4 4 2; 2 2 2] А = 5 4 2 4 4 2 2 2 2 » R=chol(A) R = 2.2361 1.7889 0.8944 0 0.8944 0.4472 0 0 1.0000 12.7.5. QR-разложение Это разложение естественным образом возникает при ортогонализации столбцов матрицы методом Грама—Шмидта. В результате получается разложение данной матрицы A = Q*R где матрица q — ортогональная, а матрица r — верхняя треугольная. Это разложение можно, в частности, применить при решении несовместных систем уравнений. Большинство современных алгоритмов поиска собственных значений основано на QR-разложении. QR-разложение получается с помощью команды [Q,R]=qr(A) — пример 12.22. » A=[l 1 3; 2 1 2; 2 -5 8; -1 3 -7] A = 113 2 12
Линейная алгебра 501 2 -5 -1 3 В -7 » [Q,RJ=qr(A) Q = -0.3162 -6.6325 -0.6325 0.3162 R = -3.1623 0 0 0 -0.3922 -0.5883 0.5883 -0.3922 3.1623 -5.0990 0 0 0.6325 -0.3162 -0.3162 -0.6325 -9.4868 5.0990 3.1623 0 0 -0 0 0 5883 3922 3922 5883 Если матрица прямоугольная, причем число ее строк га больше, чем число столбцов п, лучше пользоваться экономной модификацией этой команды [Q, R]=qr (А, 0). В этом случае вычисляются, только первые п столбцов матрицы q и первые п строк матрицы r (пример 12.23). ! Пример'12.23. Экономная модиф » [Q,R]=qr(A Q = -0.3162 -0.6325 -0.6325 0.3162 R = -3.1623 0 0 ,0)" -0.3922 0.6325 -0.58ВЗ -0-.3162 0.5883 -0.3162 -0.3922 -0.6325 3.1623 -9.4868 -5.0990 5.0990 0 3.1623 -.,:- '■■.•. \ т.ч.-, :.- ■ . . ■ -*. Для экономных представлений матриц q и r остается в силе равенство A=Q*R. Другие две модификации команды QR-разложения: [Q, R,P]=qr (А) и [Q, p., Р] =qr (А, 0). Кроме матриц q и r первая из этих команд создает матрицу перестановки р (пример 12.24), для которой А*Р = Q*R
502 Глава 12 причем диагональные элементы матрицы r идут в порядке убывания абсолютных величин. I Пример 12.24. ОЯтразложение сматрицей перестановки - -■ » [Q,R,P] = Q = -0.2673 -0.1782 -0.7127 0.6236 R = -11.2250 0 0 0 Р = О 0 1 -ч? 0 1 о- (А) -0.7000 -0.5667 0.4333 0.0333 4.9889 -3.3333 0 0 1 0 0 0.3040 -0.7024 -0.3879 -0.5137 -2.6726 -1.0000 -1.3628 0 0. -0. 0. 0. .5883 .3922 .3922 .5883 Вторая модификация создает экономное представление матриц Q и R, а вместо квадратной матрицы р — записанную в виде строки перестановку номеров столбцов (пример 12.25). Ц1рим$|й'£2& Экономное представление матриц о, и r .; » [Q,R,P] = Q = -0.2673 -0.1782 -0.7127 0.6236 R = -11.2250 0 0 P = 3 =qr 7: (A,0) -0.7000 -0.5667 0.4333 0.0333 4.9889 -3.3333 0 1 0.3040 -0.7024 -0.3.879 -0.5137 -2.6726 -1.0000 -1.362S
Линейная алгебра 503 12.7.6. Сингулярное разложение Это разложение произвольной матрицы порядка mxn в произведение трех сомножителей (пример 12.26). Сингулярное разложение создается командой [U, S,V] = svd(A) где и — ортогональная матрица порядка mxm, s — диагональная матрица порядка шхп, v — ортогональная матрица порядка пхп, причем А = U*S*V В комплексном случае матрицы и и v — унитарные. Числа, идущие по диагонали матрицы s, — вещественные неотрицательные (даже если матрица А — комплексная), расположены в порядке не возрастания. Это так называемые сингулярные числа матрицы д. Их квадраты являются собственными числами матрицы а'*а. I; Пример 12;26; » format А = 8/3 4/3 2/3 -2/3 » [U,S,V] и = -1/2 -1/2 -1/2 -1/2 S = 6 0 0 0 V = -1/3 -2/3 -2/3 rat Сикгулярн6е"разложение■"''"£* 11/6 4/3 19/6 2/3 5/6 10/3 13/6 8/3 =svd (А) 1/2 1/2 1/2 -1/2 -1/2 1/2 -1/2 -1/2 0 0 3 0 0 2 0 0 2/3 2/3 1/3 -2/3 -2/3 1/3 *'*$№* 1/2 -1/2 -1/2 1/2 С помощью сингулярного разложения строится псевдообратная матрица. 1.7 Зак. «99
504 Глава 12 Пусть a=u*s*v, где s = причем sl>s2>.,. Тогда псевдообратная матрица a+=v*s**u', где s+ = Для приведенных выше матриц: s+ = 1/6 0 0 0 0 1/3 0 о 0 0 1/2 0 о s: А = 11/36 -11/18 1/36 -1/36 5/18 -5/36 1/12 -1/6 1/4 -1/4 1/6 1/12 12.7.7. Полярное разложение Любую квадратную матрицу можно представить в виде произведения ортогональной на симметричную: а=р*н (в комплексном случае р — унитарная, н — эрмитова). Если известно сингулярное разложение a=u*s*v, полярное разложение можно построить, положив p=u*V, н=Р'*А. Существует другая форма полярного разложения квадратной матрицы: a=g*q, где g — симметричная (эрмитова), q — ортогональная (унитарная). В этом случае q=u*v (т. е. совпадает с р), g=a*q' (пример 12.27). и Пример-12:27, Подярно^ра^оагани?^ -¾ -Щ&- у-^Ч ' $Щ » А=[-1 -7; 1 7J » 0 = ,-1 1 [и, -0. 0. S,V] = 7071 7071 -7 7 =svd (А) .0 0 7071 7071
Линейная алгебра 505 S = 10.0000 о о о V = 0.1414 -0.9899 0.9899 0.1414 » Q=U*V Q = -0.8000 -0.6000 -0.6000 0.8000 » G=A*Q' G = 5.0000 -5.0000 -5.0000 5.0000 » P=Q; » H=P'*A H = 0.2000 1.4000 1.4000 9.8000 12.7.8. Разложение Шура Любую квадратную матрицу можно представить в виде A = u*T*U' где и — ортогональная (унитарная), а т — верхняя треугольная матрица. По диагонали матрицы т идут собственные числа матрицы а. Разложение Шура получается с помощью команды [u,T]=schur(A) — пример 12.28. » А=[3 -2 3; 1 2 1; 0 1 1] А = 3-2 3 12 1 0 ~ 1 1 » [U,T]=schur(A) U = -0.5773 -0.7071 0.5774 -0.7071 0.5774 0.0000 0.4082 -0.4082 Q.8165
506 Глава 12 2.0000 0 О -1.2247 2.0000 0.0000 -2.1213 -3.4641 2.0000 Если среди корней характеристического полинома вещественной матрицы а имеются комплексные. Матрица т в разложении Шура получается блочно- треугольной: каждому вещественному корню соответствует один диагональный элемент, каждой паре комплексно-сопряженных корней соответствует блок 2X2 — матрица, характеристическое уравнение которой имеет своими корнями эти комплексно-сопряженные числа. Для матрицы а, характеристический полином которой Х3-2Х-4 имеет один вещественный корень Xt=2 и пару комплексно-сопряженных корней Х2,3= =-l+i, разложение Шура дает результат, представленный в примере 12.29- !:ПриШр 12.29, Разложение Шура » А=[0 2 4; 1 0 0; 0 10] А = 0 2 4 10 0 0 10 » tU,T]=schur(A) U = 0.8729 0.2611 -0.412-2 0.4364 -0.0399 0.8988 0.2182 -0.9645 -0.1488 Т = 2.0000 0 0 -3.3320 -1.0000 1.8639 1.0659 -0.5365 -1.0000 Т™Ш*ГШШ Причем характеристическим полиномом 2х2-блока "-1.0000 -0.5365" 1.8639 - 1.0000 матрицы является Х2+2Х+2, корни которого -l+i. Чтобы в этой ситуации получить в разложении Шура "чисто треугольную" матрицу т, надо обратиться к функции schur с дополнительным входным аргументом 'complex' (пример 12.30).
Линейная алгебра 507 ^0рймер:12.5р.Р!аэлрчвниеШу][)4р получением jp,eyrpfi^^M:rtatpMMbi " . ,'■* » [U,T]=schur(A,'complex') и = 0.5173 + 0.703H -0.3759 + 0.0765i 0.3010 + 0.0176i 0.2586 + 0.3515i 0.7881 + 0.0814i -0.3186 + 0.2834i 0.1293 + 0.1758i -0.0724 - 0.4689i -0.5668 - 0.6372i T = 2.0000 - O.OOOOi -0.4928 - 1.7666i -2.8032 + 1.0083i 0 -1.0000 + l.OOOOi 1.0691 + 0.7867i 0 0 -1.0000 - l.OOOOi Аналогичного (хотя не обязательно тождественного) результата можно достичь, применив после [u,T]=schur (А) команду [u,T]=rsf2csf (и,т) — пример 12.31. ГП|рй^рЧ£31»;!Й^ 'v:"": -1 » [U,T]=schur(A); » [U,T]=rsf2csf(U,T) U = 0.8729 -0.3633 + 0.1234i -0.2301 + 0.1949i 0.4364 0.7921 - 0.0189i 0.0352 - 0.4249i 0.2182 -0.1311 - 0.4560i 0.8499 + 0.0703i T = 2.0000 0.9393 - 1.5752i 2.9361 - 0.5039i 0 -1.0000 + l.OOOOi -1.3274 0 0 -1.0000 - l.OOOOi 12.7.9. Разложение Хессенберга Любую квадратную матрицу можно представить в виде А = U*H*U' где и — ортогональная (унитарная), а н — "почти треугольная" матрица, у которой все элементы, лежащие ниже первой субдиагонали, равны о. Собственные числа матрицы н те же, что у матрицы а. Разложение Хессенберга осуществляется с помощью функции hess — пример 12.32.
508 Глава 12 d . rt.l » A=[l 2 0 3; -1-2 0-3; 0 0 2 0; 1203] A = 1 -1 0 1 2 -2 0 2 » [P,H]=hess P = 1.0000 0 0 0 H = 1.0000 1.4142 0 0 (A) -0. 0. 0. 1. -0. 0 0 2 0 0 7071 0 ,7071 ,7071 ,0000 ,0000 0 3 -3 0 3 0 -0.7071 0 -0.7071 -3.5355 -5.0000 0.0000 0 1 0 0 -1.0000 0 0 0 0 2.0000 Если матрица а симметричная (эрмитова), такой же будет и матрица н, которая в этом случае оказывается трехдиагональной (пример 12.33). l ПрйЙер:;1;?;33. РэдНоженщ^^ .-' ■ » A=[33 16 1 2; 16 -39 0 1; 1 0 -39 -16; 2 1 -16 33] A = 33 16 1 2 16 -39 0 1 1 0 -39 -16 2 1 -16 33 » [P,H]=hess(A) P =■ 0.2173 -0.9682 0.1238 0 -0.9755 -0.2110 0.0619 0 -0.0338 -0.1342 -0.9904 0 0 0 0 1.0000 H = -42.3983 -0.7625 0 0 X. '■
Линейная алгебра 509 -0.7625 35.2949 -9.0647 0 0 -9.0647 -37.8966 16.1555 О 0 16.1555 33.0000 12.7.10. Разложение Жордана При наличии кратных корней характеристического полинома квадратную матрицу А не всегда можно привести к диагональному виду, т. е. представить как произведение A = VDV""1 где d — диагональная матрица. Однако всегда можно построить несколько более общее разложение A = VJV-1 где j — так называемая жорданова (или каноническая) форма матрицы А, она представляет собой блочно-диагональную матрицу с блоками специального вида (жордановыми клетками): ~\0 1 0 . 0 Х0 1 . 0 0 х0 . 0 0 0. 0 0 0. . 0 0 " . 0 0 . 0 0 • К 1 . о Х0_ где Ко — корень характеристического уравнения. Каждому корню соответствует одна или несколько таких клеток-блоков, их порядки могут быть любыми, блок 1X1 представляет собой просто диагональный элемент Х0. Число блоков, соответствующих конкретному корню Х0, равно геометрической кратности этого корня, сумма порядков блоков, соответствующих Я0, равна алгебраической кратности этого корня. Чаще соотношение между матрицами A, v и J записывают несколько иначе: J = V_1AV и называют матрицу J жордановои формой матрицы а, столбцы матрицы v образуют жорданов базис. В MATLAB жорданово разложение находится с помощью команды [V,J]=Jordan(А). Пусть характеристический полином матрицы а имеет вещественный корень 7, его алгебраическая кратность равна 2, геометрическая кратность равна 1, поэтому имеется одна жорданова клетка 2x2 (пример 12.34).
510 Глава 12 » A=[li 4; -4 3] А = 11 4 -4 3 » [V,J]=jordan(A) V = 4 1 -4 О J - 7 1 О 7 Пусть характеристический полином матрицы а имеет комплексные корни +i, алгебраическая кратность каждого из них равна 2, геометрическая кратность каждого из них равна 1, поэтому для каждого корня имеется одна жорданова клетка 2X2 (пример 12.35). I.Яри<£е|р||&^^ в случае кЬмплексных.кррней|;|; ^^¾¾¾ » А=[0 -2 0 -1; 10 0 0; 0100; 0010] А = 0 -2 0 -1 10 0 0 0 10 0 0 0 10 » [V, J]=jordan(A) V = 0 + 0.2500i 0.5000 0 - 0.2500i 0.5000 0.2500 0 - 0.2500i 0.2500 0 + 0.2500i 0 - 0.2500i 0 0 + 0.2500i 0 -0.2500 0 - 0.2500i -0.2500 0 + 0.2500i » Л J = 0 + l.OOOOi 1.0000 0 0 0 0 + l.OOOOi О О О 0 0 - l.OOOOi 1.0000 О 0 0 0 - l.OOOOi
Линейная алгебра 511 12.8. Системы линейных уравнений 12.8.1. Основные понятия Существование и единственность решения Систему линейных уравнений &11х1 + . . . + а1пхп = Ъх; amixi + . . . + апюхп = Ът, обычно кратко записывают в виде Ах = b Ее основными характеристиками, от которых зависит существование и единственность решения, являются: □ п — число неизвестных (число столбцов матрицы коэффициентов а); □ г — ранг матрицы коэффициентов: r=rank (А); П r — ранг расширенной матрицы: R=rank( [А Ь]). Имеют место следующие положения: □ система совместна (имеет решение) тогда и только тогда, когда r=R, в случае r<R система несовместна (не имеет решения); П решение системы единственно тогда и только тогда, когда r=R=n, в случае r=R<n система является неопределенной (имеет бесконечно много решений); П очевидно, что число уравнений (число строк матрицы) m>R. Обратная и псевдообратная матрицы Для квадратной невырожденной матрицы А (ее определитель det(A)#o) обратной называется матрица а'1, для которой АА"1 = А-1А = Е где е — единичная матрица. В MATLAB матрица, обратная к а, создается обращением к функции inv(A). Если матрица а вырожденная или неквадратная, MATLAB при обращении к этой функции выдает соответствующее сообщение. Для заданной матрицы а псевдообратная а' имеет такие же размеры, как транспонированная матрица а', ранги матриц А й а" одинаковы. Псевдообратная матрица удовлетворяет уравнениям А*(А*)*А = А (А*) *А* (А+) = А*
512 Глава 12 причем матрицы а*(ан) и (а*)*а — симметричные (в комплексном случае эрмитовы). Для квадратной невырожденной матрицы а псевдообратная совпадает с обратной (ач=ам). Псевдообратная матрица строится на основе сингулярного разложения. В MATLAB матрица, псевдообратная к а, создается обращением к функции pinv(A). Наиболее полно о псевдообратной матрице см. в [47]. 12.8.2. Решение совместной системы Рассмотрим типовые решения системы линейных уравнений. О Крамеровская система. Простейшим и наиболее важным с точки зрения приложений случаем является так называемая квадратная крамеровская система Ах=ь, у которой r=R=n=m, det(A)*o. Единственное решение такой системы задается формулой х = А_1Ь, что в обозначениях MATLAB записывается как x=inv (а) *ь. Здесь ь — матрица, содержащая необязательно только один столбец, т. е. одной матричной операцией можно решить сразу несколько систем линейных уравнений с одной и той же матрицей коэффициентов, но с различными наборами правых частей. Альтернативная запись решения крамеровской системы линейных уравнений х = А\Ь. Здесь \ — левое матричное деление. О Неопределенная система. В случае r=R<n система является неопределенной (имеет бесконечно много решений). Общее решение такой системы может быть записано в виде х = Хс + у, где хс, — частное решение неоднородной системы Ах=ь; у — общее решение однородной системы Ах=о. Некоторое частное решение неоднородной системы Ах=ь может быть получено с помошью левого матричного деления: Хо - А\Ь. При выполнении операции а\ь MATLAB выдает предупреждение, в переводе означающее "Матрица близка к сингулярной (вырожденной) или плохо масштабирована. Результаты могут быть неточными" (пример 12.36).
Линейная алгебра 513 » А=[2 7 3 1;1 3 5 -2;1 5 -9 8;5 18 4 5] А = » ь = » 2 7 1 3 1 5 5 18 b=[5;3;l;12] 5 3 1 12 xO=A\b Warning: Matrix хО Results -5.5000 1.2500 1.7500 2.0000 3 5 -9 4 is 1 -2 8 5 close may to singular or be inaccurate. badly RCOND = 4. scaled. ,077954e- -019 Наибольший интерес среди частных решений неоднородной системы представляет так называемое нормальное решение, (решение с минимальной евклидовой нормой). В курсах высшей алгебры для его построения предлагается довольно громоздкий способ, включающий выделение базы строк в расширенной матрице [Alb]. В MATLAB оно может быть легко получено с помощью псевдообратной матрицы по формуле х0 = pinv(A) *ь (пример 12.37). [Пример 13Ь37,Поиск но^мМ ьного'частногоjj^^^R н^»норо^йи си^^ы ■' » pA=pinv(A) pft 0.0045 0.0147 0.0138 -0.0028 » x0=pA*b 0.0030 0.0071 0.0275 -0.0150 0.0001 0.0081 -0.0549 0.0393 0.0105 0.0371 0.0139 0.0066
514 Глава 12 хО - 0.1576 0.5478 0.2636 0.0594 Множество решений однородной системы Ах=о называют ядром матрицы а. Оно представляет собой линейное пространство размерности к = п - г. Его базис можно найти с помощью функции null (пример 12.38). Имеются два способа обращения к ней: П Y = null (А). Столбцы матрицы y представляют собой ортонормирован- ный базис пространства решений; □ Y = null (А, 'г'). Столбцы матрицы y представляют собой некоторый рациональный базис пространства решений. В обоих случаях a*y = о. Вектор нормального решения хс, ортогонален к каждому столбцу (любой) матрицы y: x0'*y = о. f.npiiw^:12i38vi^^cK;6ia3Hca пространства'решений Щ^^гЩ^Ш^^' ~'У[°у$ЖЩ » null (А) ans = -0.7798 -0.5721 -0.0057 0.4098 0.3633 -0.3732 0.5098 -0.6045 » null fА, 'г') ans = -26 17 7 -5 1 0 0 1 Общее решение однородной системы можно записать в виде у = Y*t где t — столбец параметров [ti,-t2;... ;ti:]. Для представления общего решения взят наиболее простой вариант частного решения и базиса в пространстве решений: х = 1-5.50;!.25,-1.75,-2.00] + [-26;7; l;0]*ti+[17,--5;0;l] *t2
Линейная алгебра 515 12.8.3. Псевдорешение несовместной системы Псевдорешением системы Ах=ь называется такой вектор х, который при подстановке в систему дает вектор невязки а*х-ь, минимальный по евклидовой норме (метод наименьших квадратов). Очевидно, что для совместной системы псевдорешение является обычным решением (вектор невязки равен о). Одним из способов нахождения псевдорешения является переход к так называемой нормальной системе, которая получается из Ах=ь умножением слева на транспонированную матрицу: а'Ах=а'Ь. Матрица этой системы симметрична (в комплексном случае эрмитова). Нормальная система всегда совместна и любое ее решение является псевдорешением исходной системы (пример 12.39). [!Примёр|2.39;5:Поиск псевдорешения как решения нормальной / "'',J » А=[2 3;3 17;11 17;13 20] А = 2 3 3 17 11 17 13 20 » Ь=[0;0;1;3] b = 0 0 1 3 »■S=A'*A S = 303 504 504 987 » р=А' *Ь Р = 50 77 » x=S\p х = 0.2340 -0.0415
516 Глава 12 Этот метод не рекомендуется применять для больших и плохо обусловленных матриц (см. разд. 12.9.3), потому что при умножении А'А обусловленность ухудшается. Тот же результат в MATLAB можно получить гораздо проще и надежнее с помощью левого матричного деления х=а\ь или псевдообратной матрицы x=pinv{A)*b. Для рассмотренной выше матрицы А псевдообратная матрица имеет вид: » pA=pinv(A) РА = 0.0103 -0.1245 0.0508 0.0611 -0.0022 0.0808 -0.0087 -0.0109 Соответствующее псевдорешение совпадает с приведенным выше: » х=рА*Ь х = 0.2340 -0.0415 Фактически этот метод основан на использовании сингулярного разложения матрицы (см. разд. 12.7.6). Он обладает большей устойчивостью к погрешностям округления и неточности задания коэффициентов и/или правых частей. Другой метод псевдорешения несовместных систем основан на использовании QR-разложения матрицы на ортогональный и верхний треугольный сомножители (см. разд. 12.7.5)— пример 12.40. Этот метод также обладает достаточной устойчивостью. Если известно разложение матрицы a=qr, то нормальное уравнение А'Ах=а'ь превращается в R'Rx=R'Q,b, откуда x=R"1Q'b, или, в обозначениях MATLAB, x=R\(Q'*b). ; Пример-12.40. Поиск псевдорёшения с йспользова » [Q,R]=qr(A,0) Q = -0.1149 0.0268 -0.1723 -0.9850 -0.6319 0.1064 -0.7468 0.1332 R = -17.4069 -28.9540 0 -12.1928 >> x=R\(Q'*b)
Линейная алгебра 517 х = 0.2340 -0.0415 Если псевдорешение не единственно, обычно ищут нормальное псевдорешение (псевдорешение с минимальной евклидовой нормой) — пример 12.41. Оно может быть получено либо путем левого матричного деления х=А\ь, либо с помощью псевдообратной матрицы x=pinv (а) *ь (в первом случае возможно сообщение о недостаточном ранге матрицы). рПример .12.41;. Поиск нормедьного пеёвдорещени - ^ W,'., ,,^,.,,.. .. ■; А » A=[l 1 1;1 1 1;1 1 1;1 1 2] A = 111 111 111 112 » b=[l;2;3;4] b = 1 2 3 4 » x=pinv(A) *b x = 0.0000 "0 2.0000 12.8.4. Некоторые приложения Приведем ряд полезных примеров реализации алгоритмов решения линейных уравнений. Линейные матричные уравнения В теории линейных управляемых систем часто встречаются матричные уравнения, в которых как неизвестное, так и коэффициенты являются матрицами (чаще всего квадратными). Простейшими являются линейные матричные уравнения Ляпунова а'*х+х*а+с=о и Сильвестра a*x*g+f*x*b=g. Пример нелинейного матричного уравнения рассматривается в гл. 15.
518 Глава 12 Для решения уравнения Сильвестра (уравнение Ляпунова является его частным случаем) предлагается следующий алгоритм [57]: 1. Построить матрицу (сумму кронекеровских произведений) w=a®g'+f®b'. 2. Построчно развернуть матрицу c=(Cij) в вектор-столбец c=(cu, ..., ст> 3. Решить систему линейных уравнений w*x=c. Вектор-столбец х=(хц, ..., xln, xzi, ..., хпп) построчно свернуть в матрицу х=(хч). Рассмотрим уравнение 2 1 1 1 X' X - X X 1 -1 1 1 Это частный случай уравнения Сильвестра при матрицах-коэффициентах (пример 12.42). |;Лримвр 12,4% Поиск р « ..^^^^^^Щл^г^Л » А=[2 » В=[-1 » С=[1 » Е=еуе 1;1 2] l; 1 - l; 1 - (2); » Wl=kron(A,E Г»71 — W1 — 2 0 1 0 0 2 0 1 » W2=kron(E,B W2 = -1 1 0 0 1 -1 0 0 » W=W1+W2 W .= 1 1 1 0 1 1 0 1 -1 L] ') ') ; l 0 2 0 0 0 -1 1 1 0 1 1 % 0 1 0 2 0 0 1 -1 % 0 1 1 1 % Построим произведения % Найдем их сумму
Линейная алгебра 519 » c=reshape (С, 4,1) % Построчно развернем матрицу С в вектор-столбец с с = 1 1 1 -1 Входная матрица функции reshape предварительно транспонируется, т. к. в MATLAB преимущественным является развертывание матрицы в вектор (и свертывание вектора в матрицу — см. ниже) по столбцам, как в Fortran. В данном конкретном примере матрица с симметрична, так что эта предосторожность сделана в расчете на общий случай. Систему линейных уравнений w*x=c решим с помощью команды: » x=W\c X = 1.6667 -0.3333 -0.3333 -о.зззз Полученный вектор-столбец х надо свернуть по строкам в квадратную матрицу. С учетом особенностей операций свертывания-развертывания для этого придется выполнить команду, также включающую транспонирование: » X=reshape(х,2,2)' X = 1.6667 -0.3333 -0.3333 -0.3333 Подставим найденную матрицу х в левую часть матричного уравнения: » А*Х+Х*В ans = 1.0000 1.0000 1.0000 -1.0000 Полученный результат совпал с матрицей правых частей с. Система уравнений с формируемой матрицей Рассмотрим пример решения системы линейных уравнений, матрица которых формируется по определенным правилам. Такие системы естественным образом возникают при численном решении дифференциальных уравнений.
520 Глава 12 Мы возьмем в качестве примера двумерное уравнение Пуассона —Г + -Т = «*<У>- ск1 dx2 Будем искать его приближенное решение в единичном квадрате. Введем сетку с шагом h по обеим координатам, тогда для уравнения Пуассона можно написать конечно-разностную аппроксимацию (ич — значение неизвестной функции в узле, f Ll — значение функции f в том же узле, об аппроксимации суммы вторых производных см. разд. 14.3): Это уравнение перепишем в виде: и, ui,3-l - 2u15 Ъг + Ui.j+1 " 4"4ij + u i.:i+1 = h2 ■ fis = fir Введем одномерную нумерацию узлов квадратной решетки, считая, что в каждой строчке и каждом столбце находится L узлов (очевидно (L-l)h=l). Связь одномерных (к) и двумерных (i, j) индексов выражается простыми формулами: k = |i - 1) ■ L + j; i = l + floor((к - 1)/L); j = к - (i - l) • l. Будем считать, что граничные условия, т. е. значения неизвестной функции ul3 при i=l, i=L, i=i, j~L — нулевые, а правая часть f ,.,-=-1 при всех 2<i<L-l, 2<j<L-l. Функция Poissonmatrix формирует матрицу А и правую часть b системы линейных уравнений, а также ее решение — матрицу и (пример 12.43). Пример 12.43: Функция Poisson^matrikfl? #^ %^^Щ?0%Ж^У#^'р_ function [A,b,Ul = Po.i.sson_matrix (.1,) A=zeros {L, L) ; LL=L~2; b=zetros (LL, 1) ; h=l/{L-l); hh=h"2; for k=l:LL [i,j]=deconv(k,L); if i==l I i==L | j==l | j==L A(k,k)=l.; else A{k,k)=-4; b(k)=-hh; p=convol(i-l,j,L); A(k,p)=l;
Линейная алгебра 521 p=convol(i+1,j,L); A(k,p)=l; p=convol(i,j-l,L) ; A(k,p)=l; p=convol(i,j+1, L); A(k,p)=l; end end u=A\b; U=reshape (u, L, L) ; Вспомогательные функции convoi и deconv осуществляют свертку и развертку индексов (npHivrep 12.44). р*?р'ъж:?-$Ш'''^''^^^^ '-"эдажетда1 ник: ■•• ^Пример 12.44. Функций:donvbl M'deoonv' "!*£др; ' ^ "■ ".'l/gv _ ..„ ,? - i function k=convol(i,j, L) k = (i-l)*L+j; function [i,j]=deconv(k,L) i=l+fix((k-l)/L);. j=k-(i-l)*L; В примере 12.45 приведено решение уравнения Пуассона, полученное с помощью функции Poisson_matrix при L=ll. Г, Пример 12:45..Решение уравнения Пуассона методом сеток pSft^p. Щ<; ';%,.>■ А function Poisson_tst L=ll; [A,b,U] = Poisson_matrix(L); h=0.1; Xmin=0; Xraax=l; XO=Xmin: h: Xmax ; [X Y]=meshgrid(XO) ; axes ('Xlim', [Xmin-h Xmax+h],'Ylim',[Xmin-h Xmax+h]); axis equal; hold on; V=0:0.01:0.07; contour (X, Y, U,V) ; xlabel('xl'); ylabel('x2'); title ('Решение уравнения Пуассона методом сеток',... ' FontName','' Courier')
522 Глава 12 На рис. 12.1 показаны линии уровня этой матрицы для значений v= =0.01:0.01:0.07. Рис. 12.1. Решение уравнения Пуассона 12.9. Проблема собственных значений Вектор х*0 называется собственным вектором квадратной матрицы а, если Ах=Хх для некоторого числа X, которое называется собственным числом, соответствующим собственному вектору х. Любой вектор кх также является собственным вектором для того же собственного числа л. Задача отыскания собственных чисел и собственных векторов заданной матрицы называется проблемой собственных значений. 12.9.1. Характеристический полином Собственные числа матрицы являются корнями характеристического уравнения det (A-?iE)=6. Его левая часть h(X)=det(A-XE) представляет собой полином от X, степень которого п равна порядку матрицы а. Он называется характеристическим полиномом матрицы а.
Линейная алгебра 523 Наличие и количество собственных чисел матрицы зависит от того, над каким полем она рассматривается — в вещественном случае комплексные корни характеристического полинома игнорируются. В общем случае характеристический полином можно представить в виде *„ ЫХ) = (А. - Хг)кЧХ - Хгр... {X - Хр) Показатели степени ki, k2, ..., kp называются алгебраическими кратностями собственных чисел Я.1, Хг, ..., Хр. Для заданной матрицы А. ее характеристический полином, который равен h(A.)=det (a-Xz), можно получить с помощью команды ь=ро1у(А), порождающей строку из п+1 элемента (п — порядок матрицы а). Эта строка содержит коэффициенты характеристического полинома в порядке убывания степеней, причем старший коэффициент равен 1. Корни любого (в частности — характеристического) полинома можно найти с помощью функции roots: команда r=roots(h) порождает столбец из п элементов, содержащий корни полинома, коэффициенты которого заданы в строке h. Заметим, что функции roots и poly являются взаимно обратными — обращение poiy(r) воспроизводит строку ь. Иногда бывает интересно построить матрицу с предписанным характеристическим полиномом h, который должен быть приведенным, т. е. иметь старший коэффициент, равный 1. Это можно сделать с помощью функции F=compan(h). Здесь F— так называемая матрица Фробениуса, -присоединенная к полиному h, — одна из бесконечного (вообще говоря) множества матриц, имеющих заданный характеристический полином. На самом деле функция roots ищет корни любого полинома как собственные числа присоединенной к нему матрицы Фробениуса. Для характеристического полинома, заданного вектором коэффициентов h=[l 2 4 -5], присоединенная матрица Фробениуса '-2 -4 5 1 0 0. О 10 Ее первая строка заполнена коэффициентами полинома, причем старший коэффициент (равный i) опущен, а остальные записаны с противоположным знаком; строки, начиная со 2-й, взяты из единичной матрицы. Собственные векторы Имеют место следующие положения, касающиеся собственных векторов: П собственные векторы, соответствующие различным собственным числам, линейно независимы;
524 Глава 12' П количество линейно независимых собственных векторов, соответствующих одному собственному числу (это количество называется геометрической кратностью собственного числа), не превосходит алгебраической кратности этого собственного числа. Особый интерес представляет базис, состоящий из собственных векторов (собственный базис матрицы). Приведем два достаточных условия существования собственного базиса: □ все собственные числа различны (иначе говоря, алгебраические кратности всех собственных чисел равны 1); О матрица а является симметричной (в комплексном случае — эрмитовой). В этом случае всё корни характеристического уравнения — вещественные, и даже при наличии кратных корней существует ортогональный собственный базис. 12.9.2. Вычисление собственных значений Основная функция MATLAB, решающая проблему собственных значений, — eig (пример 12.46). Существует несколько способов обращения к ней, из которых отметим два основных: О L=eig(A) — столбец l заполняется собственными числами матрицы а; □ [v,b]=eig(A) — диагональная матрица d содержит собственные числа; столбцы матрицы v суть соответствующие им собственные векторы (нормированные). Имеет место соотношение a*v = v*d. ; Пример 12.46. Вычисление собственных значений |Ч '."% й^-.-й*'/-^ -¾ £• ^;'Щ ;...~..:::..л...:>л ;■...:.■.«-„:.; ,;..:.:..; .;..: ........ :;.....:й.:;:.^.<^Х:.^...«...;;Л.Ля.гй:..?й*:;л;1 » а=[4 -1 -2; 2 1 -2; 1 -1 1] А = 4 -1 -2 2 1-2 1-11 » L=eig(A) L = 1.0000 3.0000 2.0000 » |V,D]=eig(A) V = -0.5774 -0.7071 -0.5774 -0.7071 -0.5774 -0.0000 0.7071 -0.0000 0.7071
Линейная алгебра 525 D = 1.0000 0" о О 3.0000. о О 0- 2.0000 Случай кратных корней Недостатком функции eig является то, что при наличии кратных корней характеристического уравнения соответствующие столбцы матрицы v могут оказаться линейно зависимыми (пример 12.47). [:При^ер:12.47.;.Кратнь1е;корнИ; __._„.. .. ^¾^^1¾^¾^^..^^¾¾¾ лй.;.,„ж,л;.л«л;лй-а.::;в;»к;йК:4; » А=[3 -10 0; 0 3 0 0; 10 3 1; 0 10 3] ft = 3 0 1 0 » [V,D]. V = -1 3 0 1 =eig(A) 0 0 1.0000 D = 3 0 0 0 0 0 3 0 0 0 -1 0 0 3 0 0000 0 0000 0 0 0 3 0 0 0 1 3 0 0 -1.0000 0.0000 0 0 0 3 0.7071 0.0000 0 -0.7071 Невооруженным глазом видно, что первые три столбца матрицы v линейно зависимы. Чтобы получить только линейно независимые собственные векторы, можно применить функцию [R, jb]=rref (V), которая вырабатывает r — так называемую ступенчатую форму матрицы v и jb — строку, содержащую номера столбцов матрицы v, образующих базу. Матрицу в, столбцы которой являются линейно независимыми собственными векторами, можно получить, выделив базовые столбцы из матрицы v (пример 12.48).
526 Глава 12 [Пример :12.48. » [R,jb R = 1 0 0 0 jb = 1 » B=V(: В = =rre -1 0 0 0 a jb) 0 0 i.OGOO 0 Получение j f (V) 0 0 -0 -1 0 0 1 0 0 0 0 7071 0000 0 7071 ЩШШШ Признаком линейной зависимости столбцов матрицы v является неравенство rank(v)<n. Этот критерий является не очень надежным. Чтобы более уверенно определить ранг, его надо вычислить с помощью команды rank(V,toi) с различными значениями порога toi. Так, в примере 12.47 на основании выдачи результатов утверждалось, что первые три столбца матрицы v линейно зависимы (т. е. ее ранг равен 2). Однако rank(v, 1е-17)=з. Функция rref(V) имеет модификацию rref{v,toi). Можно также найти сингулярные числа матрицы si>s2>. ..не учетом предполагаемой точности исходных данных и/или приближенных вычислений выбрать, какое из сингулярных чисел не является пренебрежимо малым — его номер и будет эффективным рангом матрицы. Случай комплексных корней Если среди корней вещественной матрицы имеются комплексные, по команде [v,D]=eig{A) будут созданы комплексные матрицы v и d (пример 12.49). Пример 12.49. Комплексные корни -. * г - , -¾^^¾¾¾¾¾ » А=[0 2 4; 1 0 0; Q. 1 0] А = 0 2 4 100 0 10
Линейная алгебра 527 » [V,D]=eig(A) V = -0.872? 0.7559 0.7559 -0.4364 -0.3780 - 0.3780i -0.3780 + 0.3780i -0.2182 -0.0000 + 0.3780i -0.0000 - 0.3780i D = 2.0000 0 0 о -i.oooo + l.qoooi о 0 0 -1.0000 - l.OOOOi Можно получить вещественные матрицы v и d, но d будет блочно- диагональной — каждой паре комплексно-сопряженных корней соответствует диагональный 2.х2-блок. Для этого после [V, D]-eig(A) надо применить команду [v,D]=cdf2rdf(v,D): » [V,D]=cdf2rdf(V,D) V D = -0.8729 -0.4364 -0.2182 = 2.0000 0 0 0.7559 -6..3780 -0.0000 0 -1.0000 -1.0000 .0 -0.3780 0.3780 0 1.0000 -1.0000 При этом комплексные корни -i±i характеристического полинома матрицы А являются и корнями характеристического полинома 2х2-блока — матрицы а Г 12.9.3. Обусловленность матрицы Метод Гаусса является точным настолько, насколько точно выполняются входящие в него арифметические операции. Поскольку в MATLAB используется представление чисел с плавающей запятой, арифметические операции в большинстве случаев выполняются неточно, так что и решение систем линейных уравнений на самом деле является приближенным. Оценить погрешность этого приближения, основываясь на пофешностях выполнения отдельных арифметических операций, весьма трудно хотя бы из-за большого их числа (для нахождения обратной матрицы число операций оценивается 0{п3), где п — порядок матрицы).
528 Глава 12 Проще выяснить, как влияют на решение системы линейных уравнений небольшие изменения в правых частях и в коэффициентах матрицы. Если решение меняется также незначительно, можно с некоторой уверенностью считать, что и погрешности округления не очень повлияют на окончательное решение. Основную роль в этом рассмотрении играет понятие нормы вектора |х|| (обычно имеется в виду евклидова норма ||х|| = д|£ у.\, которая в MATLAB вычисляется с помощью функции попп(х)). Умножение вектора х на матрицу а можег изменить его норму. Область возможных изменений нормы определяется двумя числами: М = max -т—jf- , m = mm .. .. . **° И **o и Их отношение cond(A)=M/m называется числом обусловленности матрицы а, в MATLAB его можно найти с помощью функции cond(A). Имеются и другие способы описания числа обусловленности: П отношение наибольшего сингулярного числа матрицы к наименьшему; П произведение сингулярных норм данной матрицы и обратной к ней N ' ||А_1| (эта ноРма в MATLAB вычисляется с помощью функции norm (А)). Рассмотрим систему уравнений Ах=ь и другую систему, полученную изменением правой части и с изменившимся решением: А(х+Дх)=ь+ДЬ. Поскольку А(Дх)=ДЬ, то из определений ниш следуют оценки И * м|х| и |Atfl > m|H|. llAbll Введя относительные изменения нормы правой части 5b = ~^- и нормы И IMI решения 5х= Vr. получим при m*0 5x<cond(A)* 5b, т.е. относительные И изменения в правой части ь могут повлечь относительные изменения в решении х, в худшем случае большие в cond(A) раз. То же самое справедливо в отношении изменений в коэффициентах матрицы А. Из определения числа обусловленности видно, что cond{A)>i. Нижняя оценка достигается, например, для ортогональных (унитарных) матриц. Чем больше величина cond(A), тем хуже обусловлена матрица; значения порядка десятков или даже сотен считаются неплохими. Рассмотрим систему: X! + 0.99х2 =1.99 0.99Х! + 0.98х2 =1.97
Линейная алгебра 529 Решение этой системы с помощью формулы х=а\ь дает x,=i.oooo, x2=l.oooo (легко видеть, что этот результат является точным). Немного изменим свободные члены: х, + 0.99х2 = 1.9899G3 0.99xj + 0.98х2 = 1.970106 Решение этой системы с помощью той же формулы дает xi=3.oooo, хг= =-1.0203 (приближенно). Рассмотрим вектор приращений свободных членов: ДЬ = (-1.97е-004, 1.06е-004). Его евклидову норму можно вычислить с помощью соответствующей функции MATLAB: ||дь|| = погт(ДЬ) = i.4368e-004. Относительное приращение I IN нормы свободных членов 5b = \-^- = 5.1312е-005 (здесь norm(Ь) = 2.8002). IMI Можно констатировать, что относительное приращение вектора свободных членов весьма мало. Найдем вектор приращений решения Дх = {2.0000, -2.0203) и его норму ||Дх|| = погт(Дх) - 2.8428. Относительное приращение вектора решения Sx = = Vii = 2.0102 Не мало (здесь norm (х) = 1.4142). м Отношение 5x/5b = з.9175е+004 — почти 40 тысяч! Такой плохой результат объясняется не малостью определителя матрица А, хотя он и в самом деле невелик (det(A)=-l.ooooe-oo4), но его легко сделать равным -1, умножив на юо оба уравнения, входящих в систему, причем ни решение, ни отношение йх/5ь при этом не изменятся. Гораздо важнее плохая обусловленность матрицы а. Ее число обусловленности можно найти: cond(A) = з.920бе+004, что лишь ненамного превышает найденное выше значение 5х/5ь = 3.9175е+004. 12.10. Линейная алгебра и новые типы данных Описанные выше функции линейной алгебры ориентированы на работу с вещественными данными удвоенной точности (double). Однако пакет MATLAB 7 расширил возможность выполнения операций с целочисленными данными (int8, uints, intie, uintie, int32, uint32) и вещественными данными с одинарной точностью (single). Эти расширения отчасти коснулись и некоторых функций линейной алгебры.
530 Глава 12 Так, например, функции формирования матриц eye, ones и zeros теперь позволяют создавать массивы любого типа, однако для этого они используют дополнительный параметр, определяющий класс возвращаемого результата (пример 12.50). ! Пример 12,50. Формирование матриц с; данными норых:ти1!Ов.£^¾¾5 ^-^¾^ \ » ai8=eye {4, ' int8.') ; » aui8=ones(3,6,"uint8'); » ail6=zeros(5,'intl6'j; » af=eye{4,5,'single'); » whos Name Size Bytes Class af 4x5 80 single array ail6 5x5 50 intl6 array ai8 4x4 16 int8 array aui8 3x6 18 uint8 array В операторах присваивания теперь тоже можно указывать тип возвращаемого значения: » x=int8( [1 .2 3 4] ); » whos Name Size Bytes- Class x 1x4 4 int8 array Естественно, что формируемые и присваиваемые значения должны укладываться в диапазон чисел, допустимых для данного класса. В противном случае соответствующие значения будут заменены либо верхним, либо нижним числовым пределом соответствующего класса: » fcj=uint8([100 200 300]) Ь = 100 200 255 Над массивами одинакового типа можно выполнять большинство арифметических операций. Результат их выполнения принадлежит этому же классу (пример 12.51). 1 Пример 12.51. Выполнение арифметических операций над массивами ;f ' ■'•? Щ I одинакового типа я ."*..." .(...„и..,'......',.'. ., .' -. ....* .».: » x=intl6([l 2;3 4]) ; » y=intl6([5 б;7 8]);
Линейная алгебра 531 » zl=x+y; » z2=x.*y; » z3=x"; » whos Name X У zl z2 кЗ Size 2x2 2x2 2x2 2x2 2x2 Byt es 8 8 8 8 8 Class lntl6 array intl'6 array intl6 array intl6 array intl6 array При выполнении операций такого рода результат, выходящий за допустимые пределы, заменяется соответствующим максимальным или минимальным значением: » x=uint8([10 100]); » y=uint8([20 20]) ; » х.*у ans = 200 255 » х-у ans = 0 80 Если одним из операндов является скаляр, то им должен быть либо скаляр того же типа, либо значение типа double. Другие смешения типов запрещены (пример 12.52). ;; Пример 12.52. Операция над матрицей и скаляром '•>■-«-^ -. » x*int8(3) ??? Error using => mtimes Integers can only be combined with integers of the same class, or scalar doubles. » x*uint8(3) ans = 30 255 Целочисленные матрицы нельзя умножать или возводить в степень, хотя аналогичные операции над матрицами типа single допустимы (пример 12.53).
532 Глава 12 Ш§Ш5ё^Ш^Б^^ЗШ^^Ш^^^ВШ т » x=uint8([l 2;3 4]); » х*х ??? Error using ==> mtiraes At least one operand must be scalar. » хл2 ??? Error using ==> mpower Both operands must be scalar. » z=single([l 2;3 4]); » z*z ans = 7 15 » гл2 ans = 7 15 10 22 10 22 Довольно необычно модифицирована функция sum, вычисляющая сумму элементов своего аргумента. Если аргументом является целочисленная матрица любого типа, то функция sum возвращает значение типа double. Однако если добавить еще один параметр-строку 'native', то тип возвращаемого значения совпадает с типом матрицы. Если аргументом функции sum является массив типа single, то она всегда возвращает результат типа single, и добавка параметра 'native' в этом случае ничего не меняет (пример 12.54). a » x=int8([l 2 3 4]); » y=sum(x) У = 10 » 2=SUITl{X, z = lb" » whos Name X У z 'native') Size 1x4 lxl 1x1 Bytes 4 8 1 Class int8 array double array int8 array » xl=single.( [1 2 3 4]]
Линейная алгебра 533 »■ zl=surn(xl) zl = 10 » whos zl Name Size Bytes Class zl 1x1 4 single array >> z2=sum(xl, 'native') z2 = 10 » whos z2 Name Size Bytes Class z2 lxl -4 single array Нормальную поддержку для матриц типа single обеспечивают функции trace (вычисление следа матрицы) и inv (обращение матрицы). При этом они сами определяют тип своего аргумента и возвращают результат того же типа (пример 12.55). [Пример 12 55^Йспо1пьзование функций trace и inv т »■ x=single » y=inv(x) У = -2.000.0 1.5000 » z=trace( z = 5 » whos Name X У z ([1 2;3 4]) 1.0000 -0.5000 x) ^.. 2x2 lxl t Bytes 16 16 4 Class single array single array single array Таким образом, введение целочисленных данных очень мало повлияло на решение задач линейной алгебры. Скорее, оно рассчитано на использование целочисленных массивов большого размера в задачах машинной графики. Возможность работы с вещественными данными одинарной точности может быть использована в конкретных задачах. Однако следует помнить, что диапазон данных типа single на порядок уступает данным типа double, а в задачах с плохо обусловленными матрицами удвоенная точность гарантирует получение более качественных результатов.
Глава 13 Интерполяция и аппроксимация Предположим, что на числовой оси заданы точки х,<х2<... <хг (обычно их называют узлами) и значения yi, уг, ..., уг., где каждое уа — вещественное число, соответствующее узлу х;. Задача одномерной аппроксимации состоит в том, чтобы построить просто вычисляемую функцию, в некотором смысле приближающую эти данные. В зависимости от класса аппроксимирующих функций и требований к способу аппроксимации возникают различные постановки задач. В дальнейшем изложении роль аппроксимирующих функций будут играть полиномы и сплайны. 13.1. Интерполяционный полином Требования к аппроксимации заключаются в том, чтобы искомый полином в узлах Х1<жг< ... <хп принимал соответствующие значения yi, у2, ..., у„ и имел наименьшую возможную степень. Существует единственный полином степени не выше п-1, удовлетворяющий этим условиям. Он называется интерполяционным полиномом для заданных xt и yL. Известны явные формулы, выражающие этот полином (интерполяционные полиномы Лагранжа и Ньютона), однако они скорее удобны для "ручной работы" на бумаге (или для самостоятельного программирования), а в MATLAB мы воспользуемся для построения интерполяционного полинома методом неопределенных коэффициентов. Пусть этот полином степени п-1 имеет вид: p-ix"'1 + p?xn"' + ... ■¥ pn.ix + рп. IK Зпк. 890
536 Глава 13 Его коэффициенты должны удовлетворять системе линейных уравнений Р1ХГХ + Р2Х""2 + •- + РП-3Х1 + Рп = Ух', р^Г1 + p2x£"2 + ... + р,,.^ + pn = y2. PlC1 + Рг^""2 +-.. + P„.1X„ + Pn = Уп. Матрица этой системы представляет собой так называемую матрицу Вандер- монда и может быть создана функцией vander(X), где х — столбец с компонентами хь хг, ..., х„. Этот столбец можно создать командой x=[xi,x2, ... ,хп] ' или х=[х1;х2,-... ;хп]. Аналогичным образом создается и столбец правых частей системы уравнений Y=[yl,y2, ...,уп]'. Единственное решение крамеровской системы получается путем левого матричного деления (пример 13.1). |}]ри мер ■ 13L1 решение1 1фяМёровс^й'сис1гёмы' ь^^^ф^я^^^^^^^^^^$- » Х= [0.05;0.10;0.17;0.25;0.30;0.36] X = 0.0500 0.1000 0.1700 0.2500 0.3000 0.3-600 » Y=t0.050;0.1003,-0..1717; 0.2553;0.30S3; 0.3764] Y = 0.0500 0.1003 0.1717 0.2553 0.3093 0.3764 » P=vander(X)\Y Р = -4.5785 5.0346 -1.6381 0.3434 0.9746 0.0006
Интерполяция и аппроксимация 537 Коэффициенты аппроксимирующего полинома р{х) степени n, наилучшим способом приближающего таблицу функции Y(x) в смысле наименьшего квадратичного отклонения в узлах, проще найти, обратившись к функции polyfit(x, y,n) (пример 13.2). • ""■■■■■ ';!V""-""7/'"''"""*V«p;^""^^^ I Пример 1312.,Поиск коэффициентов апп » P=polyfit(X,Y,5) -4.5785 5.0346 -1.6381 0.3434 0.9746 0.0006 Из результатов видно, что оба подхода для полинома 5-й степени дали одинаковый результат. Это вполне естественно — интерполяционный полином, найденный с помощью функции vander, проходит через узловые точки, и его отклонение в табличных точках равно 0. Однако к функции polyfit можно обратиться и для построения аппроксимирующего полинома меньшей степени, который, в общем случае, не может проходить через все узловые точки. Для проверки качества найденного полинома можно построить график, на котором находится полиномиальная кривая и нанесены табличные точки аппроксимируемой функции. Для вычисления значений полинома можно использовать функцию y=polyval (р,х), где вектор х покрывает интервал табличных значений [Х(1),х(п)] и даже слегка выходит за его пределы. Тем самым интерполяционный полином будет использован также и для экстраполяции данных. В примере 13.3 приведена программа, реализующая описанные действия. i Пример 13-3. Функция построения графика^. *'J.,_-...*■* ^¾¾^-¾^¾-^"Г^^^3*"^ function prog!3_l х=[0.05 0.10 0.17 0.25 0.30 0.36]; у=[0.0500, 0.1003, 0.1717, 0.2553, О.ЗОВЗ, 0.3764]; xlabel1'х'); уlabel С у'); hold on plot(x, у, 'ко') t =-0.05:.01:0.45; c5=polyf it (x, у, 5) ; y5=polyval(c5,t); plot(t,y5,'k-') ti tie ('Полиномиальная интерполяция','FontName•,'Courier') hl=legend(' данные", 'Интерполяция', 0-) ; set{hL,'FontName','Courier')
538 Глава 13 Рисунок 13.1, отражающий результат работы программы, показывает, что в данном примере качество интерполяции, а также экстраполяции в выбранном диапазоне, весьма хорошее. 0.Б 0.5 0.4 0.3 0.2 0.1 0 ч Полиномиальная интерполяция О данные Интерполяция У* #/ *S - у 1 0 0.1 .0.2 0.3 0.4 0.5 0.6 .. X Рис. 13.1. Пример удачной интерполяции Однако при других исходных данных качество может оказаться значительно хуже. Виной этому обычно является желание воспользоваться полиномом высокой степени (пример 13.4, рис. 13.2). Пример 13.4ГФункцйя:п6строёнЙя'графи|а при других исходных, данных^"-'Щ \ function progl3_2 х=[-2,-1,0,1,2]; y=[0,0,l,0,0J; title ('Полиномиальная аппроксимация','FontName', 'Courier') xiabel('x'); ylabel('y'); hold on plot(x, y, 'ko') t =-3:.1:3,- c2=polyfit(x,y,2); y2=polyval(c2,t); plot(t,y2,-k:') c4=polyfit(x,y,4);
Интерполяций и аппроксимация 539 y4=polyval(с4,t); plot(t,y4,'к-') hl=legend('данные',"полином 4-й степени','полином 2-й степени',0); set (hi., ' FontName', 'Courier') Если интерполяционный полином 4-й степени проходит через табличные узлы аппроксимируемой функции, то полином 2-й степени через эти узлы уже не проходит. Но среди всех полиномов 2-й степени он дает наименьшее среднеквадратичное отклонение в узлах табличной функции. Вполне возможно, что именно он дает более приемлемые результаты в промежуточных точках. Полиномиальная аппроксимация 12 10 8 6 4 2 0 ■-3 -2-1 0 1 2 3 I '. Рис. 13.2. Интерполяция полиномами разной степени 13.2. Сплайны Дальнейшего повышения качества аппроксимации табличных данных можно достичь с помощью сплайнов — полиномов невысокой (обычно 3-й) степени, приближающих данные не глобально, т. е. на всем заданном интервале, а по отдельности на каждом частичном интервале между соседними узлами. При этом в узлах должна быть обеспечена стыковка — совпадение значений (график сплайна проходит через узлы), совпадение производных (отсутствие изломов), иногда совпадение вторых производных. Могут также задаваться краевые условия на концах интервала, например — обращение в ноль второй производной- О данные - - полином 4-й степени — полином 2-й степени
540 Глава 13 Для такого рода кусочно-полиномиальной аппроксимации табличных функций у(х) предназначена функция interpi: уу = interpi(х, у, xx,mechod) ; Здесь: □ х — абсциссы аппроксимируемой функции; О у — ординаты аппроксимируемой функции; □ хх — абсциссы контрольных точек, в которых вычисляются значения аппроксимирующих полиномов, возвращаемые в качестве вектора уу; П method — способ аппроксимации, задаваемый в виде строки символов (на самом деле достаточно указать только первый символ). Функция interpi предоставляет на выбор следующие методы: О nearest' — аппроксимация кусочными полиномами нулевой степени (ступеньками): для любого промежуточного значения хх находится ближайшее табличное xj и в качестве уу берется соответствующее табличное значение yij П 'linear' — аппроксимация кусочными полиномами 1-й степени (ломаными); □ 'spline' — аппроксимация кусочными полиномами 3-й степени (сплайнами); ' □ 'pchip' или 'cubic' — аппроксимация кусочными полиномами Эрмита 3-й степени. Если параметр method опушен, по умолчанию используется 'linear'. При аппроксимации по методу 'spline' в узловых точках непрерывны первая и вторая производные, а во внутренних узлах, соседних с концевыми, непрерывна также и третья производная. При использовании метода 'pchip' вторая производная может иметь разрывы. Сплайн, построенный по методу 'pchip', является монотонным на любом участке, на котором монотонны данные, этот сплайн воспроизводит локальные экстремумы данных. Для гладких данных предпочтителен метод 'spline', для негладких лучше Применять 'pchip'. Если нас интересуют коэффициенты сплайнов, полученные в результате кусочно-полиномиальной аппроксимации, то вместо функции interpi следует обращаться к функциям spline или pchip. Они возвращают структуры, в полях которых хранятся найденные коэффициенты (подробнее об этом см. в разд. 13.2.1). Эти структуры могут задаваться в качестве аргументов при обращениях к функции ppvai для вычисления значений аппроксимирующих функций (пример 13.5).
Интерполяций и аппроксимация 541 \ Пример 13.5 » » » ps » рр х=[-2 -1 у=[0 0 1 ; ПОИСК: КОЭфф 0 12]; 0 0J; ps=spline(х,у) = form: breaks: coefs: pieces: order: dim: 'pp' [-2 -10 12] [4x4 double] u 4 1 pp=pchip(x,y) = form: breaks: coefs: pieces: order: 'PP' [-2 -10 12] [4x4 double] 4 4 dim: 1 Построение негладких данных и сплайнов по методам 'spline' и 'pchip' приведено в примере 13.6. .Ч1.„..,..™....,.„....„.уч...,„.. ..„..„,.,.... ,uu..M,^»up»v^Vi..^.„?...v»rv»..^..u::».j-«u-. Пример 13.6; Построение/негладких данных и с^тнов''',-1фл-^Щ^р^' &£' function progl3_3 х=[-2 -1 О 1 2]; у=[0 0 10 0]; t 3.5:.05:3.5; ps=spline(x,y); pp=pchip(х, у) ; plot(х,у,'ко',t,ppval(ps,t),'к:',t,ppval(pp,t),'к-Ч hl=legend('данные','spline','pchip',0); set(hL,'FontName','Courier') title ('Два сплайна','FontName','Courier') xlabel{'x'>;уlabel ('у') Результат работы программы progl3_3.m отображен на рис. 13.3.
542 Глава 13 12 10 В В >-> Л 2 0 -2 -i , ^ 1 1 ', 1 1 1 1 \ \ i i * 1 - 1 -3 \ \ -2 Два' сплайна -1 0 1 X _., # -. • Q данные — spline pchip t г / 1 i i t j / i i 1 / / / / 2 3 * i Рис. 13.3. Аппроксимация кубическими полиномами Результаты, представленные на рис. 13.4, построены приведенной выше программой для других табличных данных: х = -3:3; у = [-1 -1-10 111] ; - 1.5 1 0.5 >, 0 -0.5 -1 -1.5 О данные — spline pchip i i i i I -3 -2 Два сплайна * 1 -1 0 1 X , 2 , Э и \ Рис. 13.4. Аппроксимация кубическими полиномами для других данных
Интерполяция и аппроксимация 543 13.2.1. Стандартные сплайны MATLAB Названия методов 'spline' и 'pchip' являются именами функций, к которым обращается interpi (другие два метода nearest" и 'linear' обрабатываются непосредственно в interpi). Обращение к этим функциям имеет два разных формата: yy=spline(x,y,xx) или pp=spline(х,у) y=pchip{x,y,xx) или pp=pchip(x,y) В первом варианте смысл входных и выходных параметров тот же, что при обращении к interpi. Во втором варианте обе функции возвращают так называемую кусочно-полиномиальную форму (ppform, pieceweise polinomial form) — специальный внутренний формат MATLAB для представления сплайнов. В возвращаемой структуре, содержащей несколько полей, из которых основными являются два — pp.breaks и pp.coefs. Их можно получить так, как было продемонстрировано выше, или выполнив команду [bp,cp]=ppbrk(pp). Значением поля breaks является вектор х. Поле coefs представляет собой матрицу, каждая строка которой заполнена коэффициентами полиномов 3-й степени, аппроксимирующих данные на отдельных участках: П первая строка — на участке от breaks (1) до breaks (2); □ вторая строка — на участке ОТ breaks (2) ДО breaks (3) и т. д. Например, табличная функция х=-3:3; у=[-1 -1-10 11 ib- была обработана процедурой spline, и коэффициенты полученных полиномов приведены в табл. 13.1. Таблица 13.1 Интервал по х Коэффициенты Полином 1/4*х3-3/4*х2+1/2*х-1 1/4*х3-1/4*х-1 -1/4*х3+3/4*х2+1/2*х-1 -1/4*х3+5/4*х 1/4*х3-3/4*х2+1/2*х+1 1/4*х3-1/4*х+1 [-3, -2] [-2. -1] М.0] [0,1] [1.2] [2,3] 1/4 1/4 -1/4 -1/4 1/4 1/4 -3/4 0 3/4 0 -3/4 0 1/2 -1/4 1/2 5/4 1/2 -1/4 -1 -1 1 0 1 1
544 Глава 13 Заметим, что старшие коэффициенты полиномов 1-го и 2-го участков совпадают (также совпадают и старшие коэффициенты полиномов последнего и предпоследнего участков). Это является следствием того, что третья производная непрерывна в узлах, соседних с крайними. Вычисление значения сплайна в любой точке хх происходит следующим образом. Сначала определяется i — номер интервала между соседними значениями breaks, которому принадлежит эта точка. Например, для хх=-2.5 будет i=i (для точки хх=-з.5, лежащей слева от области определения сплайна, также берется i=l). Затем берется t-xx-breaks (i) и вычисляется значение соответствующего полинома (в данном случае i/4*t3-3/4*t2+l/2*t-i). Значение сплайна в любой точке (точках) можно найти с помощью команды yy=ppvai(pp,xx). Кроме ppvai в MATLAB имеются другие функции для работы с кусочно-полиномиальной формой сплайнов: □ fnval (f,xx) — то же, что ppvai, но применимо также и для других форм представления функций, кроме ppform; П fnder (f, k) — построение производной k-ro порядка (по умолчанию k=i); □ fnint (f,iv) — построение первообразной функции (lv — значение на левом конце, по умолчанию lv=o). Функции fnder и fnint выдают результат в той же форме, в которой задана функция f. С помощью функции fnint можно, в частности, найти площадь под графиком сплайна. Рассмотрим график (пример 13.7), построенный функцией spline в предыдущем примере. !:Пример 13.7. Вычисление площади , > Т.." '"' щ& "h:.. ~$* » х=[-2 -10 1 2]; >> у=[0 0. 1 О СП; » spl=spline(х,у); % ppform для сплайна » intspl=fnint(spl); % ppform для интеграла от сплайна » area=ppval(intspl,x(length(х)))-ppvai(intspl,x(l)) area = 0.6667 13.2.2. Сглаженные сплайны Обращение к функции, строящей сглаженный сплайн, имеет вид: output = qsaps(x,yrp,xx,w);
Интерполяций и аппроксимация 545 Здесь: □ х и у — аппроксимируемые данные; □ р — параметр сглаживания (о<р<1); □ хх — контрольные точки ("длинный вектор"); Пи — вектор весов (по умолчанию заполнен единицами). Сглаженный сплайн f минимизирует выражение pY w^ - f (х±))2 + а - P)[7f ' )2dx. При р=о получается линейная функция, обеспечивающая минимум суммы квадратов отклонений в узловых точках, при p=i — обычный кубический сплайн. Тип выходной переменной output зависит от способа обращений к функции csaps. Если обращение содержит параметр хх, то output представляет собой вектор значений сплайна в контрольных точках (т. е. фактически это уу). Если же обращение имеет сокращенный вид output=csaps (х,у,р) или хх=[ ], то output — кусочно-полиномиальная форма. В примере 13.8 приведена программа построения сглаженных сплайнов с различными параметрами сглаживания. Результаты ее работы отражены на рис. 13.5. Г Пример 13.8. Построение сглаженных сплайнов ■■ -■■*„■»' :СЙ^^кЩЙ В*::'. .::: :.-.-.-.....::.......-. :.' :... ^s^^^m.\^jiM*Vaifak~^-Jin?.72^s3&A-is!££ function progl3_4 х = -4:4; у = Ю .15 1.12 2.36 2.36 1.46 .49 .06 0]; xlabel('х'); уlabel('у'); hold on plot(x,у,"ko1); xx = [x(l):0.25:x{length(x))]; w = ones(length(x),1); csl = csaps (x,y, 1, [],w); plot (xx, ppval (csl, xx), • k-1) ; cs07 = csaps (x, y, 0.7, [] ,w) ; plot(xx,ppval(cs07,xx),'k—'); cs05 = csaps (x,y, 0.5, [] ,w) ; plot(xx,ppval(cs05,xx),'k-.'); csO = csaps (x, y, 0, [] ,w); plot (xx,ppval (cs.O, xx), ' k: ');
546 Глава 13 title (' Сглаженный сплайн', '-FontName', ' Courier') hl=legend('данные','p = 1.0','p = 0.7',... 'p = 0.5', 'p = CO); set(hL,'FontName','Courier') Рис. 13.5. Сглаженные сплайны 13.2.3. Сплайны с заданными условиями на концах Сокращенная форма обращения к функции, строяшей сплайн с заданными условиями на концах: pp=csape(x,y) В этом случае условия на концах в явном виде не задаются, по умолчанию используются условия Лаграижа: первые производные на концах такие же, как у сплайна, построенного функцией spline по четырем узлам, ближайшим к соответствующему концу. Полная форма обращения к функции pp=csape{х,у,conds,valconds); Здесь: П х и у — аппроксимируемые данные; П conds — тип условий на концах, задаваемый в виде строки символов (на самом деле достаточно задать только первый символ);
Интерполяция и аппроксимация 547 П vaiconds — значения условий, задаются в виде вектора [а Ь], где а — значение на левом конце, ь — значение на правом конце. Параметр conds может принимать одно из следующих значений: П 'complete' — задаются первые производные на концах (по умолчанию — условия Лапэанжа); О 'second' — задаются вторые производные на концах (по умолчанию — [О 0]); □ 'periodic' — совпадают первая и вторая производные на концах, значение параметра vaiconds игнорируется; П 'not-a-knot.' — в первом и последнем внутренних узлах непрерывна третья производная (т. е. получается тот же сплайн, который строит функция spline), vaiconds игнорируются; □ Variational' — вторые производные на концах равны нулю, значение параметра vaiconds игнорируется. Некоторые из перечисленных возможностей демонстрирует программа progl3_5.m (пример 13.9), результаты работы которой отражены на рис. 13.6. Пример 13%Сплайн с граничнЬ|ми условиями „.s^isi-a function progl3_5 x=[-2,-l,0,l,2]; y=[0,0,1,0,0] ; plot(x,y,'ko') ; xx = [x(l):0.05:x(length(x))]; xlabel('x'); ylabel('y'); hold on conp=csape(x, y, 'complete',[0 0]) ; plot(xx,ppval(comp,xx),'k-'); sec=csape{x,y,'second',[0 0]); plot(xx,ppval(sec,xx),'k:'); title ('Два вида граничных условий', *FontName','Courier') hl=legend('данные','complete [0 0]','second [0 0]',0); set(hL,'FontName','Courier') Условия на концах можно задать в виде двухкомпонентного вектора [conds (1) conds (2) ], для его составляющих возможны только два значения: □ в vaiconds задается значение первой производной; □ в vaiconds задается значение второй производной.
548 Глава 13 . - - Два вида граничных условий ..v;' . 1.2 1 О.В 0.6 0.4 0.2 0< ~"'"-2 ^/-1.5 • -1 ■ -0.5 0 0.5 1 ...1.5 2 :" X -_ Рис. 13.6. Аппроксимация с условиями на концах Конкретные значения производных задаются в vaiconds(l) (на левом конце) и в vaiconds(2) (на правом конце). Благодаря этому возможно задание комбинированных условий. Например, команда conib=csape (х, у,[1 2],[0 0]) создает кусочно-полиномиальную форму сплайна, у которого на левом конце равна нулю первая производная, а на правом— вторая (вместо [0 0] в vaiconds можно указать любые другие значения). Примером тому является программа progl3_6.m (пример 13.10), результаты работы которой отражены на рис. 13.7. кПриищ ДЗЛО^Ллайн'с _ ^¾¾¾¾ function ргод13_.б х=[-2,-1,0,1,2]; у=[0,0,1,0,0]; plot (х, у, 'ко'); xlabel (' х'),- ylabel Су'); hold on; хх = [х(1):0.05:x(length(x))]; comb=csape(x,y,[1 2],[0 0]); plot(xx,ppval(comb,xx), 'k-') ;
Интерполяция и аппроксимация 549 title{'Комбинация граничных условий: [1 2],[О 0J','FontName','Courier') hL=legend{'данные','сплайн',0); set(hL,'FontName','Courier') ■- ■'■ •' 1.2 '" ij 0.6 "'■ 0.6 0.4 0.2 : .0 "°'2-2 .-i:5 -1 -D.5 0 0:5 '1 ■■ 1.5 2 A ' к ' Рис. 13.7. Аппроксимация с комбинированными условиями на концах 13.3. Параметрическая аппроксимация Предположим, что на координатной плоскости заданы точки: PL(Xl,yi), Р2<Х2,Уа), •••' Ре(Хр.,Уп) и требуется аппроксимировать их некоторой линией, проходящей через них (в указанном порядке!) или недалеко от них. Введем параметр t, значения которого tt<t2<..<tn (например, можно взять ti=i), и построим две функции: x=<p(t) и y=\j/(t), которые представляют собой параметрическое описание кривой, аппроксимирующей данные точки. Для этого нам надо тем или иным способом аппроксимировать два набора данных: (u, х0 и (ti, у<), а затем совместить результаты, исключив параметр t. В приведенной ниже профамме progl3_7.m (пример 13.11) для заданных табличных функций x=x(t), у=у (t) строятся четыре приближения: □ кусочно-линейное (ломаная с вершинами в данных точках); П сплайн (кривая проходит через узловые точки); Комбинация граничных условий;. [1 2],[0.0]
550 Глава 13 0 интерполяционный полином 9-ii степени (кривая, проходящая через все 10 точек); П аппроксимирующий полином 4-й степени, найденный по методу наименьших квадратов. Результаты отражены на рис 13.8. 1 Пример 13.11. Параметрическая интерполяция - -^;: .. ;'■ function progl3_7 t = [1 2 3 4 5 б 7 8 9 10]; х = [2 3 3 2 1 -1 -1 -2 -2 0']; у - Ц2344 3 2 1 0 2] ; subplot (2, 2,1}; plot ([-2.5. 3.5], [-0.5 4.5],'w') subplot(2,2,2); p]ot([-2.5 3.5],[-0.5 4.5],'w'} subplot(2,2,3); plot([-2.5 3.5],[-0.5 4.5],'w') subplot(2,2,4); plot([-2.5 3.5],[-0.5 4.5],'w') % Промежуточные точки для интерполяции tt = [til) :.0.01 :t (length (t)) ]; %. Линейная параметрическая интерполяция xline = interpi(t,x,tt,'linear'); yline = interpi(t,y,tt,'linear'); subplot(2,2,1); hold on; plot(xline,yline,x,у,'o') % Полиномиальная параметрическая интерполяция cx9 = polyfit (t,x, 9.) ; x9 = polyval(cx9,tt); cy9 = polyfit (t,y, 9) ; y9 = polyval(су9,tt); subplot(2,2,2); hold on; plot(x9,y9,x,y,'o') sx = spline(t,x); sy = spline(t,y); xx = ppval(sx,tt); yy = ppval (sy, tt) ; subplot (2-,2,3) ; hold on; plot (хх,'уу,Х/Уг 'о') cx4 = polyfit(t,x,4}; x4 = polyval (cx.4,tt) ;
Интерполяция и аппроксимация 551 су4 = polyfit(t,y, 4); у4 = polyval(су4,tt); subplot(2,2,4); hold on; plot(x4,y4,x,y,'о') Рис. 13.8. Параметрическая интерполяция По рис. 13.8 видим, что полиномы 9-й степени дают очень плохой результат, а полиномы 4-й степени — вполне приличный. Еще лучший результат дает использование сплайнов: полученная кривая проходит через все данные точки и обладает достаточной гладкостью. Иногда Moiyr возникнуть проблемы при аппроксимации замкнутой кривой. В большинстве случаев достаточно повторить в конце данных координаты первой точки. Однако этого может оказаться недостаточно, чтобы аппроксимирующая кривая оказалась гладкой и на последнем интервале. Для обеспечения гладкости на замыкающем узле можно построить периодический сплайн с ПОМОЩЬЮ фуИКЦИИ csape, ИСПОЛЬЗУЯ КОНцеВое уСЛОВИе conds='periodic". Этот прием демонстрирует профамма progl3_8.m (пример 13.12), результаты работы которой отражены на рис. 13.9. 1
552 Глава 13 \ Пример 13,12. Использование условия conds='periodic' при аппроксимации j function progl3_8 t = [1 2 3 4 5 б 7 8 9 10 11]; х = [2 3. 3 2 1 -1 -1 -2 -2 0 2] ; у = [1 2 3 4 4 3 2 1 0 2 1]; subplot(2, 2,1); plot ([-2.5 3.5], [-0.5 4.5], V) subplot(2,2,2); plot([-2.5 3.5],[^0.5 4,5],'w') subplot (2, 2,3}; plot ([-2.5 3.5], [-0.5 4.5], TW) subplot(2,2,4); plot([-2.5 3.5], [-0.5 4.5],'w') % Промежуточные точки для интерполяции tt = [1:0.01:11]; £ Линейная параметрическая интерполяция xline = interpl(t,x,tt,'linear'); yline = interpl(t,у,tt,'linear'); subplot(2,2,1); hold on; plot(xline,yline,x,y,'o') S Полиномиальная параметрическая интерполяция cx-9 = polyfit{t,x, 9) ; x9 = polyval (cx9, tt) ; cy9 = polyfit.(t,y,9) ; y9 = polyval(cy9,tt) ; subplot(2,2,2); hold on; plot (x9,y9,x, у,'o') 'i Параметрическая интерполяция обычным сплайном зу. = spline (с, х) ,- sy = spline(t,у); xx = ppval(sx,tt); yy = ppval(sy,tt); subplot(2,2,3); hold on; plot (xx, yy, x,y,'o') % Параметрическая интерполяция периодическим сплайном px=csape(t,x,'periodic'); py=csape(t,y,'periodic'); xxp = ppval(px,tt); yyp = ppval(py,tt); subplot(2,2,4); hold on; plot(xxp,yyp,x,у,'о') Кусочно-линейная аппроксимация дает замкнутую ломаную (многоугольник), аппроксимация с помощью обычных сплайнов — кривую, у которой имеется излом в начальной (она же является и последней) точке. Аппрок-
Интерполяция и аппроксимация 553 симация с помощью периодического сплайна — гладкую кривую (на самом деле непрерывна также и вторая производная). Рис. 13.9. Обеспечение гладкости замкнутой кривой 13.4. Двумерная аппроксимация 13.4.1. Аппроксимация на прямоугольной сетке В этом случае должны быть заданы: □ вектор абсцисс х (l :m); □ вектор ординат у (i -. п); □ двумерный массив аппликат Z(l:m,i:n), в котором каждой паре (х (i), у (j)) соответствует значение z (i, j) - Для дальнейшего использования в функциях MATLAB векторы х и у необходимо преобразовать в двумерные массивы х и y следующей структуры: строки массива х являются копиями вектора х, столбцы массива у являются копиями вектора у. Иными словами, они представляют координатную сетку на плоскости ху. Массивы х и y могут быть созданы командой [x,Y]=meshgrid(x,y).
554 Глава 13 Если векторы х и у имеют одинаковые компоненты, можно написать короче: [X,Y]=meshgrid(x). Для двумерной аппроксимации данных предназначена функция interp2: zz=interp2(X,Y,Z,xx,уу,method); Здесь: П х, y и z — аппроксимируемые данные; П хх, уу — массивы, задающие набор контрольных точек, в которых вычисляются значения аппроксимирующей функции zz; □ method — способ аппроксимации, задаваемый в виде строки символов. Он может принимать одно из следующих значений: • 'nearest' — аппроксимация кусочными полиномами 0-й степени (площадками): для любой пары значений (хх, уу) находится ближайшая табличная пара (х, y) и в качестве zz берется соответствующее табличное значение z; • 'linear' или 'bilinear' — аппроксимация кусочными билинейными функциями вида z=(a+bx) (c-i-dy)=poo+piox+poiy+puxy (аппроксимирующая поверхность представляет собой фрагмент гиперболического параболоида — седла); • 'cubic' или 'bicubic' — аппроксимация кусочными бикубическими ФУНКЦИЯМИ вида г=роо-^1ох+ро1У+рпху+Р2охг+Ро2У2+Р21Хгу+р1гху24-р3с,х3+ +рвзу^'; • 'spline' — аппроксимация сплайнами. Если параметр method опущен, по умолчанию используется 'linear'. В этом случае вместо функции interp2 можно обратиться к функции linear, что демонстрируется в программе progl3_9.m (пример 13.13). Результат ее работы отражен на рис. 13.10. ; Пример 13.13. Билинейная аппроксимация - *■• ^..<-- v, ...»...»• it. ......'.... i ....:;. u„i ............**...I function progl3_9- x=[l 2 3]; y=[l 2 3]; Z=[l 2 1,-2 1 2;1 2 1]; [X, Y] = meshgrid(x); [xx, yy] = meshgrid(1:0.1:3); zz=linear(X,Y,Z,xx,yy); surf (xx, yy, zz) ; xlabel{'x'); ylabel('y'); zlabel('z') ■title (' Двумерная аппроксимация', ' EontName', ' Courier') ;
Интерполяция и аппроксимация 555 Рис. 13.10. Билинейная аппроксимация Аппроксимация по методу "linear" выполняется следующим образом. Мелкая сетка взята с шагом o.i, над каждым ее квадратиком аппроксимирующая поверхность представляет собой фрагмент седла, цвет фрагмента определяется текущей палитрой coiormap и пропорционален высоте z. 13.4.2. Аппроксимация с помощью триангуляции В этом случае должны быть заданы три вектора одинаковой длины: вектор абсцисс х, вектор ординат у и вектор аппликат z. Таким образом, каждому узлу на координатной плоскости (хь у±) сопоставляется свое значение zi. Эти данные должны быть аппроксимированы некоторой достаточно простой функцией z=f (х, у). Самая простая аппроксимация — кусочно-линейная. Ее вычисление включает несколько этапов. Вначале на множестве узлов (xi, yt) строится триангуляция (разбиение плоскости на треугольники). Для заданного множества узлов (если их больше трех) существует много разных триангуляции. Наилучшая из них в некотором смысле, так называемая триангуляция Делоне, — характеризуется тем, что минимальный по всем треугольникам угол достигает максимального значения. Триангуляцию Делоне по заданным векторам х и у можно построить с помощью функции deiaunay(x,y>, возвращающей массив, каждая строка ко-
556 Глава 13 торого содержит тройку номеров узлов, образующих очередной треугольник. Соответствующий пример демонстрирует программа progl3_10.m (пример 13.14). : Пример 13.14. Триангуляция Делоне -"=-- - -3^ ." у^" ' \'':%^^f'rj\ ■|^';'*/,Ч'| function ргод13_10 х=[-2,-1,0,0,2, 3,3,4, 6, 6]; у=[ 2,-2,0,4,2,-2,5,3,-1, 1] ; axes('XLim',[-2.5 6.5], ' YLira1, [-2.5 5.5]) tri = deiaunay(x,у); s=siZG{tri) ; hold on; grid off; xlabel (' \itx') ; ylabel (' \i.ty') ; title ('Триангуляция Делоне','FontName','Courier'); for t=l:s(l) i=Lri(t,l); j=tri(t,2>; k=-tri<t,3); xt=[x(i),x(j),x{k) ,x(i) ] ; yt=[y(i),y(j),y(k),y(i)]; plot(xt,yt, 'k'); end Функция deiaunay построила массив tri из 11 троек, содержащих номера вершин соответствующих треугольников (рис. 13.11): 3 6 25 6 32 1 36 10 95 10 6 5 В 101 4 34 5 35 7 84 7 5 7 10 S Простейший пример поверхности с треугольными фанями (рис. 13.12) строит программа prog!3 1 l.m (пример 13.15). I Пример 13.15. Построение поверхности с треугольными гранями function progl3_ll х=[-2,-1,0,0,2, 3,3,4, .6, 6]; у=[ 2,-2,0,4,2,-2,5,3,-1, 1]; z=[ 1, 2,3,4,5, 6,7,8, 9,10];
Интерполяция и аппроксимация 557 tri = delaur.ay (х,у) ; crimesh(tri,x,у,zeros(size(х))); hold on; trimesh(tri,x,y, z) ; xlabel('x'); ylabel('y'); zlabel('z') colormap copper title ('Поверхность с треугольными гранями','FontName','Courier'); В этой программе использована функция trimesh, которая строит изображение поверхности с треугольными гранями по массивам х, у, z и описанию триангуляции Делоне (массив tri). Так как каждой вершине (хь yi) соответствует аппликата zi, то по исходной табличной функции мы фактически построили поверхность, составленную из треугольных граней. Теперь в любой точке (х, у), находящейся внутри огибающего многоугольника, можно восстановить перпендикуляр до пересечения с соответствующей гранью и найти значение нашей функции z (х, у) в промежуточных точках. Все эти вычисления выполняются с помощью функции griddata, которая для заданных табличных значений (векторы х, у, z) и массивов промежуточных точек (хх, уу) вычисляет значения соответствующих аппликат zz: zz = griddata (х, у, z,хх, уу) ; Рис. 13.11. Триангуляция Делоне
558 Глава 13 ДОгу — 8-.-- 6-.-- 4-.-- Рис. 13.12. Поверхность с треугольными гранями Более полная форма обращения к этой функции позволяет использовать не только треугольные грани, построенные над триангуляцией Делоне, но и произвести некоторое сглаживание ребристой поверхности за счет указания того или иного метода аппроксимации: zz = griddata(х,у,z,xx,yy,method); Параметр method может принимать одно из следующих значений: П 'nearest' — аппроксимация горизонтальными площадками (для заданной точки (хх, уу) находится ближайший узел (xlt ух) и в качестве zz берется соответствующее табличное значение Zi); П 'linear' — аппроксимация треугольными гранями (этот метод применяется по умолчанию); □ 'cubic' — сглаживание участков поверхности кубическими сплайнами; □ V4' — специальное сглаживание с использованием градиента. Поверхность с треугольными гранями ±-~Гк^ 7 i ■ * ■ ! / \ /. • „ ,' .,/^ 7 ^~-^\ s-^~ / £>s / -\ ; * -,. ^ • -5 -2
Глава 14 Численное дифференцирование и интегрирование 14.1. Конечные разности Пусть на оси абсцисс отмечены узлы хь х2, ..., х„ и функция y=f (х) задана таблицей значений в этих узлах: X] У1 Х2 У2 Хг, Уп Составим таблицы разностей: Axi=X2~Xl Ay;=y2-yi ДХ2=Хз-Х2 Ду2=у3-У2 ДхГ1-1=хп-хп-1 ЛУп-]=Уп-уп-] Если узлы равноотстоящие, т. е. Дх1=Дхг=...=ЛхГ1-1=ь, представляют интерес также таблицы разностей 2-го, 3-го и т. д. порядков для значений функции у: Д2у1=Ду2-Ду] AJyi=Azy2-Azyi Д2у2=Дуз~Ау2 Д3у2=Д2уз-Д2у2 А2у ,,-2=Д уп-1 - Д Уп- 2 Д3У1>-з=Д2у1>-2-А2Ул-з (заметим, что каждая следующая строка таблицы разностей на 1 короче предыдущей). В MATLAB имеется функция diff, которая по заданному вектору х строит вектор разностей указанного порядка: dx =diff(х) % вычисление разностей 1-го порядка dnx=diff(х,п) % вычисление разностей n-го порядка
560 Глава 14 В примере 14.1 приводится фрагмент программы, результаты работы которой для большей наглядности перенесены в табл. 14.1. |Лри^ёЩ|4,'"1.Вычйрлеййё конечны* разностей'■""* v'^1£'S^^!f4^^4^_;}?v©5^ » х = 1:0.1:2; » dx = dif f (x) ; » у = log(x); » dy = diff(y); » d2y = dtff (y, 2) ; Таблица 14.1 X 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 i dx | 0.1 | 0.1 | 0.1 j 0.1 | 0.1 ! 0.1 ! 0.1 1 0.1 ! 0.1 1 0.1 j У ! о 1 0.0953 | 0.1823 I 0.262« j 0.3365 j 0..4055 | 0.4700 | 0.5306 | 0.5878 ! 0.6419 ] 0.6931 | dy 1 0.0953 j 0.0870 | 0.0B00 | 0.0741 | 0.0690 | 0.0645 1 0.0606 | 0.0572 j 0.0541 | 0.0513 j d2y | -0.0083 | -0.0070 | -0.0059 | -0.0051 I -0.0045 I -0.0039 | -0.0035 j -0.0031 j -0.0028 14.2. Численное дифференцирование функций одной переменной Производная — понятие локальное. Поэтому, если функция задана таблицей значений, для нахождения производной функции в каком-то из узлов обычно используют интерполяционные многочлены невысоких степеней, которые хорошо приближают функцию в окрестности этого узла. Обычно для построения этих многочленов используют формулы, основанные на таблицах разностей. Наиболее известны интерполяционные формулы Ньютона. Пусть узлы, в которых заданы значения функции, равноотстоящие, т. е. Axi_=Ax2=~.=Axn-i=h. Тогда можно построить интерполяционные формулы,
Численное дифференцирование и интегрирование 561 позволяющие приближенно находить значения функции вблизи произвольного узла Xi (в этих формулах q=(x-xi) /h). Формула Ньютона 1-го порядка (линейное приближение): П интерполяция вперед y=f (x)=yi+q*Ay1 П интерполяция назад y=f (x)Syi+q*Ayi-: Формула Ньютона 2-го порядка (квадратичное приближение): П интерполяция вперед y=f (х) =y±+q*Ayi+ [q* (q-1) *ДгуО /2 ! П интерполяция назад y=f (х) =yi+q*Ay;-i+ <q* (q+1) *A?yi-2) /2 ! Формула Стерлинга 1-го порядка (линейное приближение): y=f (x)=yi+q* (Ду^+Ду;) /2 Формула Стирлинга 2-го порядка (квадратичное приближение): y=f (x)=yi+q*{Ay;-1+Ayl>/2 + q3*A2yi-i/2! Самую простую и достаточно точную формулу численного дифференцирования можно получить, если продифференцировать полусумму формул Ньютона 1-го порядка для интерполяции вперед и назад: f' (х1) = (Ду1-1+Ду!) /2Ь-{у1,1-у1_1) /2h. (14.1) Тот же результат дает дифференцирование формулы Стирлинга 1-го порядка. Заметим, что формула (14.1) неприменима для концевых узлов, т. е. при i=l и i=n, там приходится использовать по отдельности формулы Ньютона для интерполяции вперед (i=i) и назад (i=n), причем целесообразно брать формулы не 1-го порядка, которые в этом случае дают недостаточную точность, а формулы 2-го порядка: f ■ (х1) = (ДУ1-Д;!у1/2) /h=(-3yi+4y?-y3) /2h; f • (хп) = (Дуп-1-Д?Уп-г/2) /h=(3ya-4yn-1+yn-2) /2h. Приведем пример 14.2. I Пример 14.2. Точность поиска производной численными методами Для функции: х=1:0.1:2=[1.0000 1.1000 . . . 1.9000 2.0000] у=1од(х)=[0.0953 р.0870 . . . 0..0541 0.0513]
562 Глава 14 найдена производная двумя способами: численно по приведенным выше формулам и точно — по формуле log(x) '=l/x (табл. 14.2). Таблица 14.2 X 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 1 Численно | 0.9946 I 0.9116: | 0.8353 ; 0.7708 1 0.7155 ! 0.6677 1 0.6258 | 0.588.9 1 0.5561 | 0.5268 ! 0.5121 ! Точно | 1.0000 ; 0.9091 1 о.еззз | 0.7692 1 0.7143 ! 0.6667 I 0.6250 | 0.5882 ; 0.5556 I 0.5263 | 0.5000 1 Разность I 0.0054 ; 0.0025 | 0.0019 ! 0.0015 | 0.0012 j 0.0010 | 0.0008 | 0.Q007 ; 0.0006 j 0.0005 | 0.0121 Максимальная разность между численным и точным результатом на интервале [l, 2] равна 0.0121. Если исключить концевые узлы, то максимальная погрешность получится всего 0.0025, т. е. почти в 5 раз меньше. Самую простую и достаточно точную численную формулу для второй производной дает дифференцирование интерполяционной формулы Стирлинга 2-го порядка f ■' <х,,) = (Ду^-Ду!-.) /h2= (yni-2yi.+yi-i) /h2. 14.3. Численное дифференцирование функций двух переменных Градиентом функции ?(х,у) называется вектор д<х, у), также зависящий от х и у. Его координаты являются частными производными z по х и у: gx=dz/dx, g.y=dz/3y. Для численного дифференцирования отношения дифференциалов во внутренних узлах области заменяются разностными отношениями: gx = (z(x+hx,y)-z(x-hx,y))/2hx; gy = (z(x,y+hy)-z(x,y-hy))/2hy. На краях области используются другие формулы.
Численное дифференцирование и интегрирование 563 В MATLAB имеется функция, вычисляющая цифровой аналог градиента: [gx, ду] = gradient(z,hx,hy); Здесь: П z — матрица значений дифференцируемой функции, в которой каждый столбец соответствует некоторому значению х, а каждая строка — некоторому значению у; П hx, hy — шаги дифференцирования по к и по у (можно задать один параметр h, который будет использоваться для обоих аргументов, или не задавать его вовсе — тогда по умолчанию берется n=i); П gx, gy — матрицы, содержащие компоненты градиента, как функции х и у. Размеры этих матриц такие же, как у матрицы z. Для графического отображения градиента можно использовать функцию quiver (от англ. quiver— "колчан"), которая рисует векторы градиента в виде стрелок. Простейшая форма обращения к ней — quiver (gx,gy>. Оператор Лапласа для функции z (х, у) — сумма вторых производных: Дг = З^/Эх2 + d'z/dy2. Для его вычисления в MATLAB применяется функция dei2: L = del2(z,hx,hy); Здесь: П z — матрица значений дифференцируемой функции, в которой каждый столбец соответствует некоторому значению х, а каждая строка — некоторому значению у; П hx, hy — шаги дифференцирования по х и по у (можно задать один параметр h, который будет использоваться для обоих аргументов, или не задавать его вовсе — тогда по умолчанию берется h=i); П l — матрица, содержащая значения Дг/4, как функции х и у. Размеры этой матрицы такие же, как у матрицы z. При hx=hy=h цифровой аналог оператора Лапласа вычисляется по формуле L (х, у) = { (z (x-h, у) + (z (x+h, у) +z (х, y-h) +z (х, y+h)) /4-z (хг у) ) /h2 14.4. Численное интегрирование В основе всех способов численного интегрирования, т. е. вычисления площади криволинейной трапеции, расположенной под графиком заданной функции, лежит суммирование значений функции в некоторых узлах, причем значения берутся с определенными весами, зависящими от положения узлов на отрезке интегрирования.
564 Глава 14 Общая формула численного интегрирования J f(x)dx = ^А^(х±) + R(f), где R(f) — остаточный член. Чаще всего используются формулы с равноотстоящими узлами, когда отрезок интегрирования [а, ь] разбивается на п равных частей системой точек: xi=xo+ih (1=0,1, .. . ,п) x,j=a xn=b h=(b-a)/n Простейшая из формул численного интегрирования с равноотстоящими узлами — формула трапеций: ь j"f(x)dx~h У° + У" +у, +у2 +-.. +yn-, J, где y±=f (xi) (i=o, 1,..., n). Для вычисления интеграла по формуле трапеций в MATLAB используется функция trapz (пример 14.3). L Пример 14.3. Вычисление интеграла '&&-•■;. ■ -**|L- -^¾¾ " -.".'".. -.■*' ,-1 » х=1:0.1:2; » у=1од(х); » trapz (х, у) ans = 0.3В59 Точное значение интеграла, который берется аналитически, равно 0.3-863. Длины векторов х и у должны быть одинаковы. Если вектор узлов не задан, т. е. обращение имеет упрощенный вид s=trapz (у), то в качестве ординат х используются их индексы (x=l: length (у)). Узлы по оси х могут быть и не равноотстоящими (пример 14.4). ! Пример'14:4, Вычисление интеграла с неравномерным шагом по оси х .^.р: ^j| » xn=[l:'0.1:1.5, 1.6:0.2:2]; » yn=log(хп);
Численное дифференцирование и интегрирование __^__ ^65 » trapz(x,y) ans = 0.3859 Остаточный член формулы трапеций Ятрап= -{{b-a)h2/12)f" (£), где а < £ < Ь. Как показывает данное выражение, формула трапеций является точной для линейных функций, поскольку вторая производная, входящая как множитель в выражение остаточного члена, для этих функций тождественно равна нулю (почти всюду равна нулю для кусочно-линейных функций). Для f(x) = log(x) имеем f"(x) = -l/x2. При l < ^ < 2 вторая производная -1 < f" (£) < -1/4. Так как b -a = l, h = o.l (имеется в виду случай равноотстоящих узлов), остаточный член 0.0002 < к.,,раГ; < о.0008. Напомним, что по формуле трапеций с равноотстоящими узлами было найдено s = trapz(x,y> = 0.3859. С учетом остаточного члена истинное значение интеграла заключено между 0.3861 и 0.3867 (его точное значение равно 0.3863). Если функция задана таблично, для остаточного члена формулы трапеций можно использовать приближенное выражение (Ь - а)2 ~Г ЕТРЭП = й У , где черта сверху означает среднее значение по отрезку интегрирования. Для вычисления среднего значения компонентов любого вектора в MATLAB используется функция mean. В данном случае ее надо применить к вектору вторых разностей (пример 14.5). ■;v,v7"?^¥pu''^w'^^v"^f^;"""'""":v-"""''"''V""::""":'v ,,...^.,.^. .»,v,....y.......^yV...v...^...™ r-"»z I рример 14;5. Использование приближенного значения остаточного члена . ..^ \ » х=1:0.1:2; » y=log(x) ; » d2y=diff(у,2); » mears(d2y) ans = -0.0049 Подставляя найденное среднее в формулу остаточного члена, получим R.,pan = 0.0004. Если прибавить эту поправку к ранее найденному значению 0.3859, получим 0.3863, что в пределах отображаемого количества разрядов совпадает с точным значением.
566 Глава 14 Кумулятивное (т. е. накопительное) суммирование по формуле трапеций осуществляется с помощью функции cumtrapz(x,y). Она возвращает вектор, i-й компонент которого представляет сумму первых i слагаемых формулы трапеций (пример 14.6). Значение функции cumtrapz можно рассматривать как дискретный аналог интеграла с переменным верхним пределом. I Пример 14.6. Накопительное суммирование по формуле трапеций » х=1:0.1:2; » y=log(x); » cuiritrapz (х, у) ans = Столбцы с 1 по б О 0.0048 0.0186 0.0-309 0.0708- 0.1079 Столбцы с 7 по 11 0.1517 0.2017 0.2576 0.3191 0.3859 Сравним полученный результат с точными значениями интеграла с переменным верхним пределом, равным х * (iog(x)-i)+i. Чтобы вычислять по этой формуле, ее необходимо "векторизовать": » x.*(iog(x)-l)+l ans = Столбцы с- 1 по 6 0 0.0048 0.0188 0.0-311 0.0711 0.1082 Столбцы с 7 по 11 .0.. 1520 0.2021 0.2580 0.3195 0.3863 Разница между приближенным и точным значением не превосходит 0.004. Более точная (и более сложная) формула численного интегрирования с равноотстоящими узлами — формула Симпсона: ь J"f (x)dx = ~ (у0 + у2т + 2(уг + у4 + - + у2т_2) + 4(уг + у3 + у2т_г», а Где yi = f (xt) , i = 0, 1, ..., n = 2т. Для вычисления интеграла по формуле Симпсона в MATLAB применяется функция quad. При обращении к ней шаг интегрирования не задается — вместо этого используется (задаваемая явно или по умолчанию) требуемая точность вычисления интеграла. Основную часть вычислительной работы в этой функции выполняет рекурсивная подфункция quadstep, в которой используются формулы Симпсоиа с небольшим числом узлов: з (m=i) и 5
Численное дифференцирование и интегрирование 567 (т=2). Найденные по этим формулам значения сравниваются. Если разница между ними больше допустимой погрешности, отрезок интегрирования разбивается на две равные части, функция quadstep рекурсивно применяется к каждой половине, и результаты складываются. Остаточный член формулы Симпсона: IWi = -{ (Ь - a)hV'180)f"" (£>, где а < S < Ь. Как показывает это выражение, формула Симпсона является точной для многочленов степени, не выше 3-й, четвертая производная от которых тождественно равна нулю (а для сплайн-функций 3-й степени — равна нулю почти всюду). Из описания способа вычислений функции quad вытекает, что невозможно ограничиться заданием значений интегрируемой функции в каких-то заранее известных узлах (как для trapz), а необходимо уметь вычислять ее значения в любой точке интервала интегрирования. Невозможно также использовать остаточный член для оценки точности, достигнутой функцией quad, как это делалось выше для функции trapz, поскольку неизвестен окончательный шаг h, необходимый при интегрировании. К тому же он не обязательно одинаков на всем отрезке интегрирования (см. пример 14.8 с трассировкой вычислений). Минимальная форма обращения к функции, реализующей интегрирование по Симпсону,— q=quad(fun, a,b). В качестве первого аргумента задается указатель на подынтегральную функцию, второй и третий аргументы определяют пределы интегрирования. Указатель fun может быть задан одним из трех способов: □ именем m-функции, заключенным в одинарные кавычки; П указателем dfun, где am — имя функции; □ строкой, содержащей любую формулу с одной независимой переменной: » quad('log(х) ',1,2) ans = 0.3863 Заметим, что в пределах отображаемого количества разрядов этот результат совпадает с точным значением. Функция quad допускает задание четвертого входного параметра — абсолютной погрешности eps: q=quad(fun,a,b,eps) По умолчанию эта погрешность принимается равной i.e-б. Если задать ее более высокой (например, i.e-16), интеграл будет вычисляться точнее, зато существенно медленнее. О степени замедления можно судить по количеству 19 3ак. 899
568 Глава 14 fcnt обращений к вычислению значения подынтегральной функции (пример 14.7). Значение fcnt функция quad возвращает наряду со значением интеграла. рПример 14.7, Зависимость скорости от точности вычислении. ^¾¾¾ Ъ.' }-$}"~ -/-. 'Лч » format long » [q,fcnt]=quad('log(х)',1,2) q = 0.38629433-333642 fcnt = 13 » [q, fcnt] =quad('log (x)\l,2,l.e-6) q = 0.38629433433642 fcnt = 13 » [q, fcnt] =quad Clog (x) ', 1,2*1. e-16) q = 0.38629436111989 fcnt = 1173 » 2*log(2)-1 ans = 0.38629436111989 Еще один дополнительный управляющий параметр trace в обращении к quad, позволяет более детально проследить за последовательными итерациями (пример 14.8): q=quad(fun,a,b,tol,trace) Если trace=i, в процессе работы выдается последовательность строк вида [fcnt а ь-а q], в которых показаны текущие значения соответствующих переменных на каждой итерации: П количество вычислений интегрируемой функции; П левый конец промежутка; □ его длина; □ найденное значение интеграла по этому промежутку. Если trace=o или этот параметр опущен, трассировка отключается.
Численное дифференцирование и интегрирование 569 [h^Mep^T^ » q = quad('log(х)',1,2,[),1) (Задание параметра toi=[] приводит к использованию его значения по умолчанию.) Трассировка включает пять следующих строк: 5 1.0000000000 1.00000000е+000 0.3862878935 7 l.OOOOOBOOOO 5.00.000000е-001 0.1081975273 9 1.0000000000 2.50000000е-001 0.0289294372 11 1.2500000000 2.50000000е-001 0.0792682225 13 1.50.00000000 5.00000000е-001 0.2780966816 И окончательный результат: q = 0.3863 Если интегрируемую функцию невозможно (или трудно) задать одним арифметическим выражением, в качестве параметра можно указать имя файла с расширением т, в котором вычисляется эта функция. Обращение в этом случае выглядит так: q = quad(@fun,...) где fun.in — файл, доступный для MATLAB. Функция logext.m (пример 14.9) отличается от обычной функции log тем, что ее аргумент может принимать любые вещественные значения, в том числе и отрицательные или близкие к нулю, которые либо недопустимы для log, либо порождают комплексные значения. Хотя по смыслу аргумент функции х и ее значение у — скаляры, внутри они обрабатываются как векторы, поскольку вызывающая функция quad обращается к подынтегральной функции с аргументом-вектором. Например, на самой первой итерации таким ВекТОрОМ ЯВЛЯЮТСЯ Три ТОЧКИ: х=[а (а+Ь)/2 Ь]. \ Пример 14.9. Измененная функция для интефирования логарифма^'*^" "" '*?-' • i .-..' '. t -...'. .-. : .-L-. i function y=logext(x) у = zeros(size(x)); for k = 1 : length(x); if x(k) > l.e-10 y(k> = logfx(k)); end end
570 Глава 14 Сохраним эту функцию в рабочем каталоге MATLAB под именем logext.m и обратимся к функции quad: » q = quad(Slogext,-1,2) q = -0.613.7 Такой же результат получается и при следующем обращении: » q = quad(@logexc,0, 2) q = -0.6137 В то же время попытка выполнить аналогичное вычисление со стандартным логарифмом сопровождается предупреждением: » q =quad('log' ,0,2) Warning: Log of zero q = -0.6137 Так как стандартный логарифм определен и для отрицательных аргументов, но представлен в этой области комплексной функцией, то можно вычислить, например, и такой интеграл: » q=quad('log',-1,2) q = -1.6137 + 3.1416i Еще одна возможность для пользователя функции quad — задание произвольного числа дополнительных входных аргументов pi, р2, ..., которые будут передаваться подынтегральной функции: q=quad(fun,a,b, tol, trace,pi,р2,...) Для функции, заданной таблицей значений, построим сплайн-аппроксимацию (пример 14.10). | Пример 14.10. Интегрирование сплайн-функции » х = -3:3; » у =1-1 -1-10 11 1); » рр = pchip(x,y); Значение полученной сплайн-функции в любой точке хх (или для вектора хх) можно найти с помощью команды yy=ppvai(pp,xx). К сожалению, по-
Численное дифференцирование и интегрирование 571 рядок аргументов функции ppvai таков, что непосредственно подставить ppval в quad невозможно — придется использовать функцию-посредника: function уу = newppval(хх,рр) уу = ppval(рр,хх); Теперь сплайн-функцию можно проинтегрировать, передавая посреднику структуру рр: » q = quad(Gnewppval,-3,3, [], [],рр) q = О » q = quad (gnewppval, 0, 3, [],[] ,рр) q = 2.5833 (~" Замечание j Те же самые результаты можно получить и другим способом: сначала найти первообразную от сплайна с помощью функции ppint=fnint(рр), а потом взять разность значений первообразной в соответствующих точках: » ppval(ppint,3)- ppval(ppint,-3) ans = 0 » ppval(ppint,3)- ppval(ppint,0) ans = 2.5833 Если отказаться от равномерности разбиения отрезка интегрирования, можно поставить вопрос о таком выборе узлов (и соответствующих им коэффициентов), чтобы.при заданном количестве слагаемых численное интегрирование давало точный результат для многочленов максимально высокой степени. О такого рода формулах говорят, что они имеют наивысшую алгебраическую степень точности. Доказано, что при п слагаемых можно построить формулу, обеспечивающую точный результат для любого многочлена степени не выше 2п-1. Среди формул данного типа наиболее известными являются формулы Гаусса. По ним составлены таблицы узлов для нормированного отрезка интегрирования [-1, i] и соответствующих коэффициентов для большого количества различных значений п [60, 641. На основе подобных формул построена функция quadi, возможные варианты обращения к которой полностью совпадают с вариантами обращения к функции quad, построенной на основе формулы Симпсона.
572 Глава 14 Основную часть вычислительной работы в функции quadl выполняет рекурсивная подфункция quadistep, в которой используются формулы, ана- логичные формулам Гаусса, принадлежащие Лобатто (4 узла) и Кронроду (7 узлов). Найденные по этим формулам значения сравниваются. Если разница между ними больше допустимой погрешности, отрезок интегрирования разбивается на 6 неравных частей, функция quadistep рекурсивно применяется к каждой из них, и результаты складываются. 14.5. Задача Коши для обыкновенных дифференциальных уравнений Дифференциальные уравнения — один из самых главных инструментов математического моделирования физических и технических объектов и процессов. Очень часто речь идет о процессах, развивающихся во времени, поэтому независимую переменную обычно обозначают t. Самый простой вариант — дифференциальное уравнение 1-го порядка, разрешенное относительно производной: dy/dt = f(t,y). (14.2) Более сложный случай — уравнение, не разрешенное относительно производной: F(t,y,dy/dt) = 0. (14.3) Аналитически, т. е. в виде формулы, преобразовать (14.3) к (14.2) не всегда удается. Однако при численном решений дифференциального уравнения, когда нужна не формула, выражающая производную, а только ее значения, случай (14.3) достаточно легко сводится к (14.2) — просто всякий раз, когда требуется значение f (t,y), надо решать (хотя бы численно) уравнение (14.3) относительно производной при известных t и у. Если переменная у является вектором (обычно столбцом), мы имеем дело с системой дифференциальных уравнений. Дифференциальные уравнения (и их системы), содержащие производные более высоких порядков, обычно сводят к системам уравнений 1-го порядка с большим числом неизвестных. Например, если в уравнении d2y/dt2 = F(t,y,dy/dt) обозначить у = yi, а dy-i/dt = уг, получится система уравнений yi' = у?; у2" = F(t,y,,y2) - В дальнейшем мы не будем особо различать уравнения 1-го порядка и системы таких уравнений, трактуя систему как уравнение с векторной функцией у и векторной правой частью f.
Численное дифференцирование и интегрирование 573 Задача Коши для обыкновенного дифференциального уравнения 1-го порядка заключается в отыскании функции у = y.(t), удовлетворяющей этому уравнению и начальному условию у (to) = у0, где t0 и у0 — заданные значения. Способы численного интегрирования (решения) дифференциальных уравнений разрабатывались, начиная с Эйлера, который предложил метод ломанных: производная dy/dt заменяется разностным отношением Ду/At и, начиная с t0, уо, вычисления производятся по формулам: tk+i = tk+h; Yfc+i = Ук+hf {t?.,yA). где шаг h = At может быть как постоянным, так и переменным. В неявном методе Эйлера используются формулы: Wi - tfc+щ Ук+i = Ук+hf (tit+i, уи+i) . Чтобы найти очередное значение y^j по неявным формулам, необходимо решить уравнение относительно этой переменной. Это можно сделать одним из следующих способов. П Методом итераций: взяв в качестве начального приближения y^'i = yk. далее находим yi+'i = У* + htft^.y^),. yL+i = Ук + hf {t^-y^) и т. д., пока разность между соседними итерациями не станет достаточно малой. Условием сходимости метода итераций является h— < 1 (в случае век- ду 3f ( 3f£ 1 торной системы — = т-*- ду I ()yd — матрица-якобиан, |«|| — ее норма). П Путем решения линеаризованной линейной системы уравнений относительно Ду = yk+i - ук. Эта система имеет вид (i-h * (3f/Эу)) * Ду = hf. Здесь i — единичная матрица, значения f и df/dy берутся при t = tk+1, у = у:.:. Такой способ раскрытия "неявности" называется методом Розен- брока. Еще один вариант неявного метода — формула трапеций: t-it+i = tt + ь; Ук+i = Ук + (f(tt +ук) + fft^i, yk+i))h/2. Чтобы найти очередное значение ущ.ь здесь также необходимо решить уравнение относительно этой переменной. Наиболее распространенными методами численного интегрирования обыкновенных дифференциальных уравнений является семейство методов Руиге—
574 Глава 14 Кутты [51]. Порядок их точности определяется степенью h, входящей в формулу остаточного члена. Чаще всего в литературе рекомендуют формулы Рунге—Кутты 5-го порядка: кг = h*f (tfcl ус); к2 = h*f (tk + h/2,yk + kj/2) ; k3 = h*f <tk + h/2,yk + кг/2> ; k„ = h*f (tk + h, yk + кз) ; y*+i = уч + (ki + 2кг + 2k3 + fc, )/6. Использование более сложных неявных методов необходимо для так называемых жестких систем уравнений, у которых возможна потеря точности в процессе численного решения. Заранее по внешнему виду жесткую систему распознать не всегда удается, тем более что свойство жесткости может проявляться или не проявляться в зависимости от того, на каком интервале переменной t ищется решение. На практике обычно сначала пробуют решить задачу с помощью простого явного метода, а если обнаружится, что численное решение идет вразнос или программа работает слишком медленно (из-за чрезмерного измельчения шага), применяют более сложный неявный метод. Независимо от порядка точности метод Рунге—Кутты (явный или неявный) является одношаговым — для нахождения у1;(1 требуется знать только yk, а предшествующие значения ук-ъ yt.2 и т. д. ire используются. Для интегрирования систем дифференциальных уравнений, описывающих траектории спутниковых орбит, предпочитают многошаговые методы, в основном связанные с именем Адамса. Они также могут быть явными и неявными. Приведем две формулы, в которых для краткости обозначено fk=f(tk,yk). Во всех случаях tk+i=tk+h. Явный метод Адамса 2-го порядка: Ук+1 = Ук + (3fk - fk-i)h/2. Неявный метод Адамса 3-го порядка: У*и = Ук + (5fi:n + 8fk - fk-i)h/12. Куртис и Хиршфельдер," которые в 1952 г. ввели понятие жестких задач, предложили для их решения неявные методы "дифференцирования назад". Одна из их формул 2-го порядка имеет вид: yk+i = (^ук + yk-i + 2hfk_i)/3. Чтобы методы Адамса или Куртиса и Хиршфельдера могли стартовать, необходимо иметь несколько начальных значений неизвестной функции. Обычно их находят с помощью какого-нибудь варианта явного метода Рунге—Кутты.
Численное дифференцирование и интегрирование 575 Библиотека MATLAB включает несколько функций, реализующих различные методы решения задачи Коши для обыкновенных дифференциальных уравнений (ode, ordinary differential equations). Синтаксически эти функции различаются лишь именами (точнее говоря, алфавитно-цифровыми добавками к символам ode), способ обращения к ним одинаков. Эти функции используют методы разного порядка (иногда метод и/или порядок варьируется от шага к шагу), имеются и другие внутренние различия. В функции ode45 используется явный метод Рунге—Купы 4-го и 5-го порядков в модификации Дорманда и Принца. Если характеристики задачи неизвестны, рекомендуется первую попытку решения сделать с помощью этой функции. В функции ode23 используется явный метод Рунге— Купы 2-го и 3-го порядков в модификации Богацки и Шампина. Если не требуется большая точность и задача не очень жесткая, эта функция может оказаться более эффективной, чем ode45. В функции odeii3 используется метод Адамса, Башфорта и Моултона типа предиктор-корректор переменного порядка. Если требуется большая точность, а каждое вычисление интегрируемой функции является "дорогостоящим", эта функция может оказаться более эффективной, чем ode<35. Вышеуказанные алгоритмы предназначены для решения нежестких систем. Если они дают неприемлемые результаты или работают слишком медленно, надо применять одну из следующих функций, ориентированных на решение жестких задач. В функции odeiss используются численные методы дифференцирования и формулы "дифференцирования назад". Ее следует применять, если функция ode<35 потерпела неудачу или очень неэффективна и есть подозрения, что задача жесткая. В функции ode23s применяется модифицированный метод Розенброка 2-го порядка. Алгоритм этой функции одношаговый, поэтому если не требуется большая точность, он может быть эффективнее, чем odei5s. Функция ode23s может решить некоторые типы жестких задач, для которых odeiss неэффективна. В функции ode23t реализован неявный метод трапеций с использованием "свободной" интерполяции. Ее следует применять для умеренно жестких задач, если требуется высокоточное решение. В функции ode23tb реализован неявный метод Рунге—Кутты с первым шагом по методу трапеций и вторым шагом по методу "дифференцирования назад" 2-го порядка. Подобно ode23s, эта функция может быть эффективнее, чем odeibs, если не требуется большая точность.
576 Глава 14 В нижеследующем описании имя функции дано обобщенно в виде ode***, где *** _ любой из приведенных выше алфавитно-цифровых суффиксов. Простейшее обращение к любой функции ode*** имеет следующий вид: [tout,yout] = ode*** (fun, tspan, уО.) Здесь: П fun — указатель на функцию вычисления правых частей дифференциального уравнения; □ tspan — вектор, содержащий "контрольные значения" независимой переменной; минимальный вариант tspan=[to tfinai] (начальное и конечное значения независимой переменной), но могут быть заданы и промежуточные значения, тогда tspan= [to ti ... tfinai]; П yo — начальное значение зависимой переменной (скаляр или вектор- столбец); □ tout — вектор-столбец контрольных значений независимой переменной; если используется минимальный вариант для tspan, выдаются все значения, которые получались в процессе численного интегрирования; если tspan содержит и другие значения кроме to и tfinai, то tout=tspan'; □ yout — решение, представленное массивом, в котором каждая строка соответствует одному элементу в столбце rout. Рассмотрим пример 14.11. I Пример 14.11. Использование функций группы ode*** "•'■"" Дифференциальное уравнение у"=-д описывает движение материальной точки в гравитационном поле Земли (константа д=9.8). Обозначив yi=y,. у2=у', получим систему дифференциальных уравнений: У1'=У2 Сформируем вектор-столбец начальных значений у0=[0; 10] (начальная, координата 0, начальная скорость 10) и вектор контрольных значений tspan=0:0.2:2 Функцию вычисления правых частей в нашем случае можно оформить в виде анонимной функции: » dydtH?(t,y) ty(2); -9.8];
Численное дифференцирование и интегрирование 577 Обратимся К функции ode45: » [tout,yout] = ode4 5(dydt,tspan,уО) Результаты представлены в табл. 14.3. Таблица 14.3 tout 0 0.2000 0.4000 0.6000 0.8000 1.0000 yout(l) 0 1.8040 3.2160 4.2360 4.8640 5.1000 yout(2) 10.0Q0.0 8.0400 6.0800 4.1200 2.1600 0.2000 tout 1.2000 1.4000 1.6000 1.8000 2.0000 ■ yout(l) 4.9440 4.3960 3.4560 2.1240 0.4000 yout(2) -1.7600 -3.7200 -5.6800 -7.6400 -9.6000 Полная форма обращения к функциям ode*** имеет следующий вид: [tout,yout,varargout] = ode***(fun,tspan,yO,options,varargin) Здесь: D options — аргумент, позволяющий задавать управляющие параметры; □ varargin — дополнительные аргументы для вычисления fun; □ varargout — дополнительные результаты, возникающие при некоторых вариантах задания options. Аргумент options позволяет отразить очень много управляющих параметров, из которых опишем лишь некоторые. Все они задаются путем обращения к функции odeset, аргументом которой является последовательность пар вида <'параметр', значение> С Замечание Э Название любого из параметров, приведенных ниже, должно быть заключено в апострофы. Параметр ReiToi задает допустимую относительную погрешность вычислений, значение — положительное число, по умолчанию 1е-з. Параметр AbsTol задает допустимую относительную погрешность вычислений, значение — положительное число, по умолчанию ie-б. Может быть также задан вектор-строка абсолютных погрешностей для каждой компоненты решения.
578 Глава 14 Параметр initiaistep задает начальный шаг, по умолчанию начальный шаг выбирается автоматически. Параметр Mass определяет квадратную "матрицу масс" м, которая является множителем при производной в левой части дифференциального уравнения M(t,y) *y'=f (t,y). Значением этого параметра является сама матрица (имя матрицы), если она заполнена константами, или указание на m-файл, содержащий функцию, которая вычисляет матрицу масс, как функцию переменных t и у. Например, options=odeset('Mass', @mass) ; Для применения В функциях odell3, ode23, ode23s, ode23tb, ode45 матрица масс должна быть невырожденной, для применения в функциях odeiss, ode23t матрица масс может быть вырожденной. Параметр MassSinguiar позволяет сообщить, является ли (может ли быть) матрица масс вырожденной. Значение этого параметра — одна из трех строковых констант: 'yes', no', 'maybe' (последнее — по умолчанию). Параметр Events задает "события", наступление которых влияет на ход вычислений. Значением этого параметра является указание на m-файл, содержащий функцию, которая отслеживает эти события. Например, options=odeset('Events', @events) ; Приведем пример функции events (ее имя, как и имена переменных, могут быть любыми) — пример 14.12. г- к',-";--- ~ "~ •-■"" ' ■■■ "i«™ — j-"T<<C'""^W<'': : Пример 14:12. Условие окончания интегрирования '.■;* ;%&-"£-..,-я ■« ^жЧ'ЗИ function [value,isterminal,direction1 = events(t,у) % Фиксация времени, когда у(1) проходит через ноль % в направлении убывания и прекращения интегрирования value = у(1); % для слежения за обращением в 0 величины у(1) isterminal = 1; % прекратить интегрирование при value=0 direction = -1; % при условии убывания value В этой функции отслеживается обращение в о переменной value (необходимым условием останова является обращение в о некоторого выражения). Переменная isterminal задается равной 1, если при достижении vaiue=o интегрирование должно прекращаться, и равной о, если интегрирование должно продолжаться. Переменная direction должна принимать одно из трех значений: □ 1, если value возрастает при переходе через 0.;
Численное дифференцирование и интегрирование 579 О -1, если value убывает при переходе через о; П о при любом обращении value в о. Все три выходные переменные могут быть векторами одинаковой длины. В этом случае их компоненты соответствуют друг другу: при value (i)=o интегрирование прекращается, если isterminai(i)=i и продолжается, если istermlnai (i)=o. Аналогично используются и компоненты direction(ij. Если в примере с движением материальной точки в гравитационном поле задать "событие" с помощью функции events, которое будет фиксироваться в момент падения на землю: yi=o,yi'<o (direction=-i). Параметр Jacobian задает в "аналитическом виде" якобиан 3f/3y, используемый в неявных методах. Значением этого параметра является сама матрица-якобиан, если она вся заполнена константами, или указание на т- файл, содержащий функцию, которая вычисляет эту матрицу, как функцию переменных t и у. Например, options=odeset('Jacobian', GFJac); Параметр Jacobian Имеет СМЫСЛ ТОЛЬКО ДЛЯ функций odel5s, ode23s, ode23t, ode23tb. Если в одной из этих функций параметр jacobian не задан, матрица-якобиан строится численно, что замедляет работу. Функции odel5s и ode23t можно также применять для решения дифференциально-алгебраических систем. Они возникают, если известен хотя бы один первый интеграл системы дифференциальных уравнений, т. е. соотношение между неизвестными функциями, которое обращается в тождество при подстановке в него любого решения системы. В физике такие первые интегралы обычно называются законами сохранения (энергии, импульса и т. д.). Снова рассмотрим систему дифференциальных уравнений движения материальной точки в гравитационном поле. У1'=У2 у2'=-д Очевидным следствием этой системы является соотношение y2*y2'+g*yi'=o. Если проинтегрировать его, получится 0.5*у2г+д*у1=с. Это закон сохранения энергии (первое слагаемое — кинетическая энергия материальной точки с массой 1, второе слагаемое — ее потенциальная энергия). Константа с выражается через начальные условия: с=о.5*у2 (0)2+д*у1 (0). Если использовать те же начальные значения уО=[0,- ioj, получится с=ьо. Заменив одно из дифференциальных уравнений (например, второе) первым интегралом, получим дифференциально-алгебраическую систему У1,=Уг 0.5*у22 + д*у!-С=0
580 Глава 14 Внесем соответствующие изменения в функцию, вычисляющую правые части: function dydt = funa(t,y) dydt = fy(2); (1/2)*(у(2))"2+9.3*y(1)-50]; Первая и вторая компоненты выходного вектора этой функции играют разную роль: первая по-прежнему представляет правую часть дифференциального уравнения, а во второй записано выражение, которое в процессе интегрирования должно оставаться равным о. Чтобы отразить это обстоятельство в обращении к функции, решающей дифференциально-алгебраическую систему, введем матрицу масс, которая является множителем при левой части системы дифференциальных уравнений м=[1 о; о 0], и укажем, что эта матрица вырожденная. Оба условия зададим командой options=odeset('Mass',И,'MassSingular', 'yes') Выполнив команду [tout,yout] = ode23t(@funa,tspan,y0,options) получим результаты, совпадающие с найденными ранее при помощи функции ode45. 14.6. Краевая задача для обыкновенных дифференциальных уравнений Краевая задача для обыкновенного дифференциального уравнения заключается в отыскании функции у=у (х), удовлетворяющей на отрезке [а, ь] этому уравнению и граничным условиям, наложенным па значения функции и/или ее производной на концах отрезка, т. е. в точках а и ь. Для одного уравнения первого порядка краевая задача некорректна, поскольку значение у(а) полностью определяет поведение функции на всем отрезке, в том числе и значение у (Ь). Для уравнения второго порядка у''=f(х,у,у') граничные условия могут иметь следующий вид (а, в, а0, ш, р\., Pi — заданные константы): у[а)=А, у(Ь)=В у'(а)=А, у'(Ь)=В Олу(а) +Ctiy' (а)=А 1 Роу(Ь) i-P,y' [Ь)=В Могут быть и другие варианты граничных условий, но для уравнения 2-го порядка их число должно быть 2. Для уравнения произвольного порядка п граничные условия (в количестве п) могут включать значения на концах от-
Численное дифференцирование и интегрирование 581 резка неизвестной функции и ее производных до (n-i)-ro порядка включительно. Для численного решения краевой задачи уравнение высшего (п>2) порядка обычным образом сводят к системе из п уравнений 1-го порядка, соответствующим образом преобразуются и граничные условия. В MATLAB имеется функция bvp4c, решающая краевую задачу для системы обыкновенных дифференциальных уравнений y'=f(x,y), где у— вектор, у' — его покомпонентная производная, f(х,у) — вектор-функция. Решение ишется в форме сеточной функции: отрезок [а, ь] делится точками a-xi<x2<...<xn=b на части (не обязательно равные) и каждой точке xi ставится в соответствие значение yj.. Исходя из начальных значений xt и уь путем аппроксимации производной y'=dy/dx в каждой точке сетки разностным отношением Ду/Дх, строится система уравнений, из которой находятся значения уЛ. В процессе ее решения сетка xi может перестраиваться (в частности, сгущаться), при решении используется матрица-якобиан 3f /Эу. Начальные значения хг и yi задаются с помощью функции bvpinit: solinit = bvpinit(xinit,yinit); Здесь: D xinit — вектор-строка a=xinit(l)<xinit (2) <...<xinit (n)=b; □ yinit — гипотетические значения для y(i), могут задаваться в одной из двух форм: • вектор— каждая его компонента yinit(i) копируется в качестве гипотетического решения для всех точек сетки, т. е. у {ir:) = yinit (i); • функция задается в форме y=guess(x), где х— любая точка отрезка [а, ь], у — вектор, длина которого равна порядку системы дифференциальных уравнений. Для каждой точки сетки x(i) вычисляется вектор гипотетического решения у (i,: )=guess (x(i)); □ solinit — структура, в которой при указанном выше способе обращения к функции заполняются два поля: • solinit.х = xinit • solinit.у = y(i,:) Решение краевой задачи можно найти, используя функцию bvp-зс, простейшая форма обращения к которой: sol = bvp4c(odefun,bcfun,solinit) Здесь: П odefun — функция, вычисляющая вектор правых частей;
582 Глава 14 П bcfun — функция, вычисляющая вектор граничных условий; аргументами этой функции являются уа и yb — векторы решения у в точках а и ь; две компоненты вектора граничных условий представляют собой выражения, обращающиеся в о в точках а и ь соответственно; П solinit — выходная структура функции bvpinit; П sol — аналогичная структура, содержащая решение краевой задачи; кроме полей sol.x и sol.у она имеет поле soi.yp, в котором содержатся значения производной решения (sol. у)' в точках sol.x. Рассмотрим пример 14.13. I Пример 14.13 краевая задача для дифференциального уравнения 2-го порядка Я Пусть имеется дифференциальное уравнение второго порядка у' ■+у=о с граничными условиями у(0)=о, y(pi)=i. Дифференциальное уравнение заменим системой: У1'=У2 Уг'=-У1 и поместим в рабочий каталог m-файл, содержащий функцию, вычисляющую правые части: function dydx = exampl(x,y) dydx - [y{2) -у{1)]; а также m-файл, содержащий функцию, задающую граничные условия: function res = border(уа,yb) res = [ ya(l) yb (1)-1] ; В качестве начальных значений координаты х выберем с помошыо функции linspace пять равноотстоящих точек на интервале [0, pi] xinit=linspace(0,pi, 5) xinit = О 0.7854 1.5708 2.3562 3.1416 В качестве начальных приближений вектора решений в этих точках выберем, например, yinit=[0 1]. С помощью функции bvpinit сформируем структуру solinit, используемую при решении задачи: » solinit = bvpinit(xinit,yinit) solinit.x = 0 0.7854 1.5708 2.3562 3.1416
Численное дифференцирование и интегрирование 583 solinit.y = 0 0 0 0 0 11111 При таком выборе вектора yinit поле структуры solinit.y заполнено копиями исходного вектора. Вообще говоря, такой выбор начального приближения может оказаться не очень удачным. Альтернативный вариант состоит в задании вспомогательной функции, вычисляющей эти компоненты. В качестве примера возьмем функцию sincos: function sc = sincos(x) sc = [sin(x) cos(x)]; и выполним команду: » solinit = bvpinit(xinit,@sincos) solinit.x = 0 0.785« 1.5708 2.3562 3.1416 solinit.y = 0 0.7071 1.0000 0.7071 0.0000 1.0000 0.7071 0.0000 -0.7071 -1.0000 Начальное приближение, как правило, влияет на число итераций. Так что выбор начального вектора или вида вспомогательной функции полностью зависит от интуиции пользователя. Для решения нашей задачи выполним команду sol = bvp4c(@exampl,Gborder,solinit) Результат приведен табл. 14.4, в которую для сравнения включен столбец sin(soi.x), содержащий аналитическое решение краевой задачи. Таблица 14.4 sol .X 0 0.1963 0.3.927 0.7854 1.1781 1.3744 1 sol.у(1) | 0 ! 0.1951 j 0.3827 j 0.7071 | 0.S23S j 0.9808 | sol.у(2) i 1.0000 j 0.9808 ! 0.9239 | 0.7071 ; 0.3827 j 0.1951 | sol.yp(l) 1 1.0000 j 0.9808 I 0.9239 | 0.7071 ; 0.3827 | 0.1951 | sol.yp(2) 1 ° j -0.1951 1 -0.3827 | -0.7071 | -0.9239 I -0.980Б j sin (sol.x) ! о j .0.1951 j 0.3827 j 0.7071 ! 0.9239 j 0.9808 1.5708 | 1.0000 | 0.0000 j 0.0000 j -1.0000 j 1.0000
584 Глава 14 ( Замечание J Сравним sol.x с xinit=[0 0.3927 0.7854 1.ПВ1 1.5708]. Можно заметить, что функция bvp4c вставила два дополнительных узла: х=0.1963 и х=1.3744. Если попытаться построить решение краевой задачи в виде графика с помощью команды plot (sol.x,s.ol.y(l,:)), результат получится не очень гладкий — слишком мало точек содержит вектор sol.x. Эту трудность можно преодолеть с помощью дополнительной функции bvpvai. Используя информацию, содержащуюся в структуре sol, она строит интерполяционный сплайн Эрмита для заданного вектора пробных точек хх, который может содержать сколько угодно точек для обеспечения требуемой гладкости результата. Обращение к этой функции имеет вид: уу = bvpvai(sol, хх) Здесь: П sol — выходная структура функции bvp4c; П хх — вектор пробных точек: П уу — значения сплайн-функиии в пробных точках. Вектор, содержащий (по умолчанию для этой функции) 100 пробных точек, создадим командой xx=linspace (0,pi/2), соответствующие значения решения получим с помощью команды yy=bvpvai (soi,xx). Заметим, что каждый элемент уу на самом деле является двухкомпонентным вектором (подобно элементам sol.у), поэтому для рисования графика придется выполнить команду plot (хх, уу (1,:)). Полная форма обращения к функциям bvp4c и bvpinit позволяет: П учесть дополнительные условия, используемые при решении; □ использовать дополнительные аргументы в функциях odefun и befun; Q находить значения неизвестных параметров (например, собственных чисел). sol = bvp4c(odefun,befun,solinit,options, PI, P2, . . .) ; Здесь: □ options — аргумент, позволяющий задавать управляющие параметры; О Р1, Р2, ... — дополнительные аргументы для вычисления odefun и befun. Аргумент options позволяет отразить различные упраапяющие параметры, из которых опишем основные. Все они задаются путем обращения к функции bvpset, аргументом которой является последовательность пар вида ■<'параметр', значение>
Численное дифференцирование и интегрирование 585 (название любого из параметров, приведенных ниже, должно быть заключено в апострофы). Параметр ReiTol задает допустимую относительную погрешность вычислений; по умолчанию ie-з. Параметр AbsToi определяет допустимую абсолютную погрешность вычислений; по умолчанию 1е-6. Может быть задан вектор-строка абсолютных погрешностей для каждой компоненты решения. Параметр FJacobian задает в аналитическом виде якобиан Э£/Эу, где f — функция, вычисляемая в odefun. Значением этого параметра является указание на m-файл, содержащий функцию, которая вычисляет эту матрицу, как функцию переменных х и у. Например, options=bvpset("FJacobian1,@FJac); Параметр BCJacobian задает в аналитическом виде два якобиана [Э(Ьс) /Э(уа) ] и [Э(Ьс)/Э(уЬ) ], где Ьс(уа,уЬ) — функция, вычисляемая в bcfun. Значением этого параметра является указатель на m-файл, содержащий функцию, которая вычисляет эти матрицы как функции переменных уа И yb. Неизвестный параметр (вектор неизвестных параметров) вводится с помощью функции bvpinit, полная форма обращения к которой solinit = bvpinit(xinit,yinit,parameters) Здесь: □ parameters — гипотетическое значение неизвестного параметра (вектор гипотетических значений неизвестных параметров); П solinit— Структура, В КОТОрОЙ Кроме ПОЛеЙ solinit. x=xinit и solinit.у=у(i, :) заполняется еще одно поле: solinit.parameters=parameters. ( Замечание J Имя неизвестного параметра в обращении к функции bvpinit произвольно (может быть, например, bvpinit (хО, уО, lambda)), однако имя поля структуры solinit.parameters предопределено. Полностью сформированная таким образом программа представлена функцией bvptst.m (пример 14.14), а графический результат ее работы отражен на рис. 14.1. ; Пример 14.14. Использование Якобиана в краевой задаче function bvp_tst options = bvpse.t (' FJacobian', @FJac, ' BCJacobian', @BCJac) ;
586 Глава 14 xinit=J.inspace(0,pi/2, 5) ; yinit=[l 1] ; solinit = bvpinit(xinit,yinit); sol = bvp<3c (@exampl, Gborder, solinit, options) ; xx = linspace(0,pi/2); yy = bvpval (.sol, xx) ; figure; plot(xx, yy(l, : ) ) ; xlabel('x'); ylabel('y'>; % function dydx = exampl(x,y) dydx = fy(2) -yd)]; % function res = border(ya,yb) res = [ya(l> yb(1)-1]; щ function dfdy = FJac(x,y) dfdy = [0 1 -1 01 ; % , function [dbcdya, dbcdyb] = 3CJac(ya,yb) dbcdya. = (1 0 0 01; dbcdyb = [0 0 1 0]; В случае, когда в задачу включены дополнительные неизвестные параметры, должно быть увеличено число граничных условий — по одному дополнительному условию на каждый неизвестный параметр. Эти параметры должны быть аргументами функций odefun и bcfun (независимо от того, Используются ли они реально для вычисления значений этих функций). Аналитические якобианы, необходимые в случае задания условий Fjacobian и/или BCJacobian, расширяются— теперь ЭТО [3f/3y, df/dp] И [Э(Ьс) /Э(уа) , Э(Ьс)/с)(уЬ), Э(Ьс)/Э(р)]. где для краткости через р обозначен неизвестный параметр.
Численное дифференцирование и интегрирование 587 Рис. 14.1. Результат работы программы bvp_tst.m В выходной структуре sol при наличии неизвестных параметров появляется дополнительное поле sol.parameters, содержащее найденные значения неизвестных параметров. Рассмотрим дифференциальное уравнение второго порядка у''+ру=о с неизвестным параметром р (пример 14.15). •■ч.« и.мл ■*.«:*»■ '■ ■ л"^л:-7«у «л.'лущ;:^"-*:'1'»*" ^Ж^'ШШ^. енциального уравнения ЙПрймёр 1.4,1¾. Решение: краевой задачи для. диффёре [^прря^^'- V^:f-^f ^f#^| Дифференциальное уравнение заменим системой: У1,= У2 y2'=-pyi Внесем неизвестный параметр р в функцию exampi, вычисляющую правые части системы: function dydx = exampi(х,у,р) dydx = [у(2)-р*у{1)]; К прежним граничными условиями у(0)=о, y(pi/2)=i добавим еще одно: у' (pi/2)=c, соответственно изменим функцию, задающую граничные уело-
588 Глава 14 вия. Хота неизвестный параметр р не участвует в вычислении ее значения, его необходимо включить в число аргументов. function res = border(уа,yb,p) res = Г уа{1) yb(2) yb(l)-l]; Как прежде, возьмем jd.nit=linspace(0,pi/2,5), yinit=[o 1] и зададим начальное значение р=о. Включим в программу команду options = bvpset('FJacobian',@FJac, 'BCJacobian', gBCJac); Функции FJac и BCjac теперь зависят и от параметра р: function [dfdy, dfdp] = FJac(х,у,р) dfdy = [0 1 -р 0]; dfdp = [0 -у[1)]; function [dbcdya, dbcdyb, dbcdp] = BCJac(ya,yb,p) dbcdya = [10 0 0 0 0]; dbcdyb = [000110]; dbcdp = [0; 0; 0]; Выполнив команду sol = bvp<3c (Gexampl, Sborder, solinit,options) ; получим найденные ранее значения soi.x, sol.у, soi.yp и sol.parameters=l.000. 14.7. Дифференциальные уравнения неявного типа Для решения неявных дифференциальных уравнений, т.,е. не разрешенных относительно старшей производной, в MATLAB 7 появилась новая функция odel5i. Простейшая форма обращения к этой функции: [t,y] = odelbi(odefun,tspan,yG,ypO) Смысл входных и выходных параметров тот же, что и для других функций ode*"*. В пояснении нуждается лишь параметр уро — начальное значение производной. Для неявного дифференциального уравнения оно должно за- , даваться вместе с начальным моментом г.о и начальным значением функции уб так, чтобы удовлетворялось условие F(t0,y0,yp0)=0 (здесь f(t,y,d:y/dt)=o — неявное дифференциальное уравнение, его левая часть
Численное дифференцирование и интегрирование 589 вычисляется функцией odefun). Подобрать такие уо и уро помогает вспомогательная функция decic, обращение к которой имеет вид: [ у Omod, ypOmod] = decic(odefun,tO,yO,fixed_yO,ypO,fixed_ypO); Здесь: О yO, уро — задаваемые пользователем гипотетические начальные значения, которые могут и не удовлетворять уравнению F(to,yO,ypO)=o; П yOmod, ypOmod — модифицированные начальные значения, вычисляемые функцией decic, которые достаточно точно удовлетворяют этому уравнению. Процессом их вычисления можно управлять с помощью параметров fixed_yO и fixed_ypO. Так, если задано fixed_yO=i, то yOmcd=yO. Если же fixed_yO=o, то yOmod может отличаться от уо. Аналогичную роль для вычисления ypOmod играет параметр fixed_ypo. Если мы имеем дело с системой уравнений, когда переменные у и ур являются векторами, fixed_yo и fixed_ypO также задаются как векторы, и соглашение об их значениях 0 и 1 относится по отдельности к каждой их компоненте. Если любой из этих управляющих векторов задать в виде пустой матрицы [], это будет равносильно равенству нулю всех его компонентов. По сути дела, функция decic находит приближенное решение нелинейного уравнения. Рассмотрим уравнение Вейссинджера (пример 14.16). ! Пример 14.16. Решение-уравнения Вейссинджера v cf.^^SH г ^^йл ^Щ^$м Уравнение имеет вид (этот пример приведен в файле помощи): ty^y'^Vfy'^+td^+Dy'-ey = о Одним из его частных решений является функция y(t) = (t2+o.5)!/2. Попробуем начальные условия to=i, y0=y(i>=sqrtp/2) и урО=о. Значение функции уо получено подстановкой to в приведенное выше частное решение, а начальное значение производной выбрано наугад. В том, что выбранные начальные условия не удовлетворяют левой части уравнения Вейссинджера, нас убеждает подстановка: weissinger(tO,уО,урО) ans = -1.2247 Здесь weissinger — функция, вычисляющая левую часть уравнения Вейссинджера. Соответствующий m-файл содержится в каталоге MATLAB7\toolbox\matlab\demos, хотя написать единственную строчку в теле функции труда не составляет: function res = weissinger(t,у,ур) res = t*yA2*yp.^-y^3*yp/42+t*(t/42+i)*yp-tA2*y;
590 Глава 14 Удивительно лишь то, что на авторство этой "программы" претендуют два человека, и номер версии 1.6.1 свидетельствует о том, что программа неоднократно модифицировалась. Мы воспользовались этой программой лишь для того, чтобы продемонстрировать возможности функции decic. Значение уо было взято из частного решения, будем его считать точным, поэтому положим f ixed_yO=i. Значение урО=о — является гипотезой (видимо, неточной), поэтому положим fixed_ypO=0. После обращения к функции decic: [yOmod, ypOmod] = decic(@weissinger,t0,y0,1,ур0,0) мы получим модифицированные начальные условия: yOmod = 1.2247 ypOmod = 0.8165 которые дают удовлетворительный результат при подстановке в уравнение Вейссинджера: » weissinger(t0,y0mod,ypOmod) ans = 1.2649е-004 Теперь можно непосредственно решать неявное дифференциальное уравнение. Для сравнения найдем также значения точного решения. ft,у] = ode!5i(Bweissinger,[1 10],y0mod,ypOmod); ytrue = sqrt(t.A2 + 0.5); Результаты вычислений представлены в табл. 14.5. Таблица 14.5 t 1.0000 1.0379 1.0759 1.1518 1.2277 1.3036 1.4554 1.6072 1.7589 1.9107 У 1.2247 1.2561 1.2879 1.3522 1.4177 1.4840 1.6191 1.7569 1.8969 2.0362 ytrue 1.2247 1.255Э 1.2875 1.3515 1.4168 1.4830 1.6181 1.7558 1.8958 2.0374 t 3.1251 3.4286 3.5804 3.8840 4.1876 4.4912 5.0983 5.7055 5.9305 6.3805 У 3.2040 3.5002 3.6487 3.9467 4.2453 4.5446 5.1449 5.7456 5.9689 6.4158 ytrue 3.2041 3.5008 3.6496 3.9478 4.2469 4.5465 5.1471 5.7491 5.9725 6.4195
Численное дифференцирование и интегрирование 591 Таблица 14.5 (окончание) t 2.0625 2.2143 2.5179 2.8215 У 2.1809 2.3248 2.6154 2.9087 у true 2.1804 2.3245 2.6153 2.9087 t 7.2805 8.1805 9-.0805 10.0000 У 7.3107 8.2067 9.1044 10.0217 ytrue 7.3147 8.2110 9.1080 10.0250 Рассмотрим пример 14.17. ; Пример 14.17. Колебательный контур с железом ,..■■ '■-■ ж% .,« igf?" -t В книге Андронова А. А., Витта А. А. и Хайкина С. Э. "Теория колебаний"1 рассматривается колебательный контур, состоящий из электрического конденсатора и магнитной катушки. Катушка снабжена железным сердечником, магнитный поток в котором является нелинейной функцией Ф(Ц от протекающего через катушку тока i. На практике эту функцию достаточно хорошо аппроксимируют выражением: Ф(1) = A*arctg(w*i/S) + B*w*i/S Здесь а, в и s — некоторые константы, зависящие от материала сердечника, aw— число витков провода в катушке. После некоторых преобразований уравнения Кирхгофа и введения безразмерных переменных интеграл энергии в предположении отсутствия всякого рода потерь приводит к неявному дифференциальному уравнению следующего вида: A*ln(l+q'2) + B*q'2 + q2 = Е Здесь: Dq — заряд на обкладках конденсатора; П q' = dq/dt — ток в контуре; П е — значение энергии, зависящее от начальных условий. Для t = о зададим начальные условия q0 = о, qo* = 1 и вместо обращения к функции decic подберем константу е, удовлетворяющую уравнению энергии. При этом функция F[t,q,qp) может выглядеть следующим образом: function res=ABX(t,q,qp) А=1.4; В=25; 1 Андронои А. А., Витт А. А., Хайкин С. Э. Теория колебаний. — М.: Физматгиз, 1959.
592 Глава 14 E=A*log(2)+B; res=A*log(l+qp*2)+B*qpA2+q'v2-E; Заметим, что время t, которое не входит явно в уравнение, является фиктивным параметром. Для обращения к функции odeisi составим еше одну вспомогательную функцию: function test_ABX q0=0; qpO=l; tspan=[0,1001,- ft,q]=odel5i(6ABX,cspan,qO,qpO); plot(t,q) XLabel.f ■ t'), YLabel (' q') Результат интефирования на интервале [о, looj отображен на рис. 14.2. Рис. 14.2. Колебательный контур с железом При решении неявного дифференциачьного уравнения возможно досрочное окончание процесса интегрирования по достижению некоторого условия — равенства нулю заданного выражения. В этом случае список параметров функции odeisi дополняется следующим образом: [t, у] = odel5i(odefun, tspan, уО, урО, options)
Численное дифференцирование и интегрирование 593 где значение options формируется с помощью функции odesec, аргументами которой являются пары "имя — значение". В нашем случае понадобится параметр 'Events', а его значением будет указатель на функцию, определяющую три выходных значения: function [v,i,d]=qq(t,q) v=q-4; i=l; d=l; Контролируемое событие заключается в том, что значение v обращается в нуль при условии возрастания этой величины (признак d=i), и процесс интегрирования прекращается при наступлении указанного события (признак i=D- Обращение к odeibi в нашем случае может выглядеть так: [t,q]=odel5i(@ABX,tspan,qO,qpO,odeset('Events', 6qq)); Результат работы модифицированной программы приведен на рис. 14.3. ( Замечание ^ Следует отметить, что справка по функции odelsi содержит дезинформацию по поводу оформления функции events — реакции на событие прерывания процесса интегрирования. Там указано, что эта функция должна получать три входных параметра events (t,q,qp). Если следовать этому указанию, то MATLAB выдает сообщение о том, что аргументов слишком много. 4 3.5 3 25 сг 2 1.5 1 0.5 Q • i i • у / У X / / у / / Г / / У / / / ' I . 1 "01234! t 1 Рис. 14.3. Интегрирование до выполнения условия q=4
Глава 15 Нелинейные уравнения и оптимизация 15.1. Корень уравнения с одним неизвестным Для решения уравнений вида fun(x)=o используется функция fzero. Алгоритм, реализованный сю, представляет собой комбинацию хорошо известного метода дихотомии (деления пополам), метода секущих и метода обратной квадратичной интерполяции. В простейшем варианте обращения кроме указателя на функцию, корень которой ишется. задается окрестность хс, с которой начинается поиск: х = fzero(fun,хО) Аргумент fun может быть задан одним из способов: П как формула с неизвестным х, заключенная в апострофы; □ как имя m-файла (в апострофах и без расширения гп); □ как указатель на функцию (например, @fun_name); П как указатель на анонимную функцию (например, f unhandle). ( Замечание ^ Формула, заключенная в апострофы, в качестве независимой переменной может содержать только х. Использование независимой переменной с другим именем вызовет сообщение об ошибке. Аргумент хО может быть задан одним из двух способов: П как вектор [а ь], представляюший интерва;! (а<ь), на концах которого функция fun меняет знак, что гарантирует нахождение, по крайней мере, одного корня на этом интервале; □ как скалярное значение, в окрестности которого предполагается нахождение корня. В этом случае функция fzero сама пытается найти отре-
596 Глава 15 зок с центром в заданной точке хо, на концах которого функция fun меняет знак. Чтобы облегчить работу по выбору начального приближения, разумнее всего построить график функции y=fun (х>. График функции у = х*е~* + sin(x) представлен на рис. 15.1. Он получен с помощью программы из примера 15.1. "•'/■.".••*" vamw.' fzj ц» ■ ■ ■ * •* • * v :w' ■ Пример 15.1. Прстрреийе графика функции для локализации корня » х=0:0.1:2*pi; » plot(х,х.*ехр(-х)+sin(х)) » grid oh » title ('y=x*exp(-x)+sin(x)') v. f Рис. 15.1. График функции для локализации корня Из графика видно, что один из корней находится на интервале [з, <j]. И этой информацией естественно воспользоваться при обращении к функции fzero: » x=fzero('х.*ехр(-х)-i-sin(x)',[3,4]) х = 3.2665 Вместо явного задания формулы для функции fun мы могли бы объявить соответствующую функцию, запомнив ее в виде автономного m-файла или
Нелинейные уравнения и оптимизация 597 включив ее в качестве подфункции в файл нашей программы. После такого объявления обращение к функции fzero могло бы выглядеть так: function fzerol x=fzero(@fl,[3,41) function y=fl(z) y= z*exp(-z)+sin(z) ; Если мы хотим получить не только значение корня, но и узнать значение функции в найденной точке, то к функции fzero можно обратиться с двумя выходными параметрами: » [х,fJ=fzero('x. *exp(-x)+s.in(x) ', [3, 4] ) х = 3.2665 f = 2.0817е-016 Судя по значению функции, точность нахождения корня достаточно высока. В ряде задач такая точность может оказаться излишней. MATLAB предоставляет пользователю возможность формировать различные условия прекращения итерационного процесса — по точности вычисления координаты х, по модулю значения функции fun, по количеству обращений к функции fun и т. д. Более подробно эти возможности описаны в разд. 15.6. В некоторых случаях применение функции fzero может дать парадоксальные (на первый взгляд) результаты. Например, попытка решить уравнение tg(x)=o на интервале [1,2] приводит к следующим результатам (пример 15.2). 'Пример 15:2. Поиск решения'tjj(ic)=0 на интервале [i, 2] ' • -' Ч™ и.Й&л^;&^^^^;^;::&^й.,../ЙйО....>::.й:^.Л^.„ л..::... ,;. ь;...-..л. А.:. ..... » [x,f]=fzero(.'tan{x)', [1,2]) X = 1.5708 f = -1.2093е+015 Якобы "корень", соответствующий приближенному значению я/2, на самом деле является точкой разрыва, при переходе через которую функция меняет знак. Выведенное значение функции в найденной точке убеждает нас в том, что найден не корень.
598 Глава 15 Функция fzero может возвратить еще два выходных параметра (пример 15.3): [х,f, e_flag,inform] = fzero(fun,xO) Положительное значение e_f lag (обычно, это l) означает, что удалось найти интервал, на концах которого функция fun меняет знак (пример с tg(x) не должен притупить вашу бдительность). Если такой интервал не обнаружен, то e_flag=-i. Структура inform содержит три поля с именами iterations, funcCount И algorithm. В первом ИЗ НИХ находится количество итераций, выполненных при поиске корня, во втором — количество обращений к функции fun, в третьем — наименование алгоритма, использованного для нахождения корня. i Пример 15.3. Дополнительные параметры, возвращаемые функцией fzerp'S^i j » [x,f,e_f lag,inform] =fzero ('x.*exp(-x)+sin(x)', [3,4]) x = .3.2665 f = 2.0817e-016 e_flag = 1 inform — iterations': 8 funcCount: 8 algorithm: 'bisection, interpolation' Обратите внимание на то, что для достижения очень высокой точности потребовалось всего 8 итераций. Простое деление отрезка пополам для достижения такой же точности потребовало бы намного больше итераций. Условие обнаружения интервала, на концах которого функция принимает значения разных знаков, является принципиальным для алгоритма, использованного в функции fzero. Даже в таких тривиальных уравнениях, как хг=о, обычно не удается найти решение (пример 15.4). ! Пример 15.4. Задание интервала с одинаковым знаком фунщий'на^кон!)^''3^'-''^ » [х, f,e_flag]=fzero СхЛ2', [-1,1]) ??? Error using ==> fzero The function values at the interval endpoints must differ in sign.
Нелинейные уравнения и оптимизация 599 Отказ произошел из-за того, что на обоих концах заданного интервала функция принимает положительные значения. Если начальное приближение "случайно" совпадает с корнем, то функции fzero не остается ничего другого, кроме как выдать подвернувшееся решение (пример 15.5). » [x,f,e_flag]=fzero('x'-2,,0) x = О f" = О e_flag = 1 Однако изменение стартовой точки вновь ставит алгоритм поиска в тупик. Попытка расширять интервал с центром в точке х=1 приводит к появлению бесконечно больших значений функции (пример 15.6), но интервал, на котором бы произошла смена знака, так и не может быть обнаружен (обратите внимание на значение выходного параметра e_f lag). Шрш^рЧ5:6^0|Щб^ :>> [к,£,е_Г1ад]=Е2его('хЛ2',1) Exiting fzero: aborting search for an interval containing a sign change because NaN or Inf function value encountered during search (Function value at -1.716199e+154 is Inf) Check function or try again with a different starting value. x = NaN f = NaN e_flag = -1 15.2. Решение систем нелинейных уравнений Функция f solve, вообще говоря, предназначена для решения систем нелинейных уравнений вида f(x)=o, где х — вектор или матрица неизвестных, а 20 3як 809
600 Глава 15 f — функция, значением которой является вектор или матрица. Алгоритм ее работы использует начальное значение хо и базируется на минимизации суммы квадратов составляющих функции F методами Гаусса—Ньютона и Левенберга— Марквардта (более подробные сведения о них приведены в разд. 15.4.3). В простейшем случае обращение к fsolve имеет вид: х = fsolve(F,X0) В частности, функцию fsolve можно использовать и как альтернативу функции fzero для нахождения корня единственного нелинейного уравнения (пример 15.7), например, sin(x)=o. I Пример 15.7. Поиск корня с помощью функций %S6lW-'"Sb^f-' ■ ;^^>зйй1йР Vk » х = fsolve (@sin, 1) Warning: Cannot, determine from calling sequence whether to use new (2.0 or later) FSOLVE function or grandfathered FSOLVE function. Assuming new syntax; if call was grandfathered FSOLVE syntax, this may give unexpected results. To force new syntax and avoid warning, add options structure argument: x = fsolve(@sin,3,optimset('fsolve')); To force grandfathered syntax and avoid warning, add options array argument: x = fsolve(Gsin,3,foptions); Optimization terminated successfully: First-order optimality is less than options.TolFun. x = 0 Смысл довольно длинного предупреждения заключается в том, что по форме вызова MATLAB не сумел понять, какая Из двух функций fsolve имеется в виду — очень устаревшая (grandfathered) или более современная (версии 2.0 или выше). Для того чтобы отличать одну версию от другой, MATLAB предложил использовать дополнительно третий параметр. Тем не менее наше обращение было воспринято как вызов более свежей версии, которая нашла решение, ближе всего расположенное к начальной точке х0=1. Интересно, что второй аргумент функции fsolve может быть задан в виде вектора начальных значений, и для каждого компонента этого вектора будет найдено близлежащее решение (пример 15.8).
Нелинейные уравнения и оптимизация 601 [Пример 15.8, Поиск решений для вектора начальных 'зйъЧа&к ^*:^аЩ^'1''°% - ! » х = fsoive[@sin,[1 2 3 4 5 6].optimset(■fsolve')) Optimization terminated successfully: First-order optimality is less than options.TolFun. x = 0 3.1416 3.1416 3.1416 6.2832 6.2832 В отличие от fzero функция fsolve может найти приближенное решение для упоминавшегося выше уравнения х2=о и не спасовать в окрестности точки разрыва функции tg(x) (пример 15.9). { Пример 15.9. Поиск решения »e2=Q и.йдЧх),^Щ^?^КШ^^-^г^^^^5Й^----1 » х = f solve (' x"2',l,optimset(' Display', 'off') ) x = 0.0078 » x = fsolve(Stan,l,optimset('Display',"off )) x = 2.3205e-010 Смысл третьего параметра в двух предыдущих обращениях заключается в подавлении "лишних" сообщений. Более подробно о дополнительных входных параметрах функции f solve см. в разд. 15.6. Главным назначением функции fsoive является решение систем нелинейных уравнений, что мы продемонстрируем на примере 15.10. { Пример 15.10. Решение системы нелинейных уравнений;'^ ^^Щ^Ф^-Щу^1\ Уз = Xi + хг - sin(nxi) Уг = xi - Х2 - cos (71хг) Объявим функцию funs с, значения которой сформируем в виде вектора- столбца: function у = funsc(х) y=[x(l)+x(2)-sin(pi*x(l)); х(1)-х(2)-cos(pi*x<2))]; А теперь обратимся к функции fsoive, задавая каждый раз разные начальные значения (xl, х2). Так как fsoive подобно fzero умеет возвращать и вектор-столбец функций в найденной точке, то мы воспользуемся двумя выходными параметрами, чтобы оценить точность решения. Обратите вни-
602 Глава 15 мание на то, что координаты начальной точки тоже представлены в виде вектора-столбца: » [x,f] = fsolve(Gfunsc, [0.2,-1] ,optimset ['Display1, 'off') ) x = 0.3915 0.5510 f = 1.0e-010 * 0.8924 -0.0333 Результаты последующих обращений к функции solve из разных стартовых точек приведены в табл. 15.1. Таблица 15.1 № 1 2 3 4 5 6 x0=[xl;x2] xl 0.2 1 1 -0.2 -0.5 -1 х2 1 0.5 -0.2 0 -1 -2 Решение xl 0.3915- 0.5000 0.7776 -0.2329- -0.5000 -0.4595 х2 0.5510 0.5000 -0.1345 -0.-3352 -0.5000 -1.6778 Значения функции yi 0.8924е-010 0.1654е-008 0.7000е-007 -0.1062е-009 -0.2195е-00б -1.1454 Y2 -0.0333е-010 0.0000 0.1638е-007 0.0018е-009 -0.0000 0.6883 Из табл. 15.1 видно, что для первых пяти начальных точек было найдено пять разных решений, тогда как шестой эксперимент вместо корня обнаружил нечто похожее на точку локального минимума. Разобраться со всеми ситуациям помогут графики наших функций. На рис. 15.2 представлены: □ графики двух функций: x2=sin(pi*xi)-xi (сплошная линия) и xi= =cos (pi*x2)+x2 (штриховая линия). Эти функции получены путем разрешения уравнений системы относительно соответствующих переменных; П решения системы — крупные точки пересечения этих графиков и соответствующие стартовые точки (мелкие) с соединяющими их отрезками. Для их построения была использована программа progl5_l.m (пример 15.11).
Нелинейные уравнения и оптимизация 603 function progl5__l axesCXlim', [-1 1.5],'Ylim', [-1 1.5]) axis equal; grid off; hold on xl=-l:0.1:1.5; y=sin(pi*xl)-xl; plot(xl,y,'k-'); x2=-l:0.1:1.5; y=cos(pi*x2)+x2; plot(y,x2,'k:'); xlabel('xl'); ylabel('x2'); title ('Решение нелинейной системы','FontName','Courier'); xlx2=[0.2,1,1,0.5,1,-0.2,-0.2,0,-0.5, -1,-1, -2]; for j=l:6 xl=oclx2(2*j-l); x2=xlx2(2*j) ; lirie(xl,x2, 'Marker', '.', 'MarkerSize', 10); x = fsolve(@funsc,[xl,x2],optimset('Display','off')); line(x(l),x(2),'Marker','.','MarkerSize',20); plotdxl x(l)],tx2 x(2)],'k-'); end function у = funsc(x) y=[x(l)+x(2)-sin(pi*x(l)); x(l)-x(2)-cos(pi*x<2))]; 1.5 к *, .i.Wzr- Ч-ЙГ* " " - -1.5 Решение нелинейной систему ,-, ч .---'' \ ^ \; . ■"^^"А / \~~- I / 3\ <^1 -1 -0.5' " 0 0.5 . х1. ,~~ Л > J \ 1 ■;■*■■ •?-■ Г f I §; -¾^ Рис. 15.2. Графики функций
604 Глава 15 В выделенные пределы неудачная стартовая точка не попала, но если бы на полученные графики были нанесены линии уровня минимизируемой функции у? + у\, то можно было бы обнаружить, что точка 6 действительно соответствует локальному минимуму. Если бы мы не отключили выдачу сообщений функции fsoive, то в последнем запуске было бы выдано следующее пояснение: Optimizer is stuck at a minimum that is not a root. Try again with a new starting guess Среди выходных аргументов функции fsoive могут присугствовать такие же по смыслу параметры, которые допускала функция f zero: [х,fval,exitflag,output] = fsoive(fun,xO) Значение признака exitf lag=l свидетельствует о том, что решение системы найдено. При exitflag=o решение не найдено, т. к. итерационный процесс был прерван в связи с достижением максимального количества итераций или обращений к функции fun. При exitfiag=-i достигнутый минимум не является решением системы. В структуре output появились дополнительные поля с именами: П stepsize, в котором выдается величина шага при завершении поиска; П firstorderopt, в котором выдается точность, достигнутая по значению функции. Например, на одном из предыдущих запусков мы могли бы получить следующую информацию: .» [х,f,e_flag,inform] = ... fsoive(Sfunsc, [1;0.5],optimset('Display', 'off')} x = 0.5000 0.5000 f = 1.0e-OOB * 0.1654 O.'OOOD e_flag = 1 inform = iterations: 7 funcCount: 21 algorithm: 'trust-region dogleg' firstorderopt: 1..6541e-009
Нелинейные уравнения и оптимизация 605 Обратите внимание на то, что в отличие от функции fzero здесь число итераций не совпадает с количеством обращений к функции fun. Дело в том, что алгоритм поиска решения в функции fsolve активно использует якобиан системы уравнений, который в данном примере находится численным методом (аналог замены производных разностями). В функции fun может быть предусмотрена возможность задания операторов, вычисляющих якобиан по аналитическим формулам (пример 15.12). Это может существенно уменьшить количество обращений к функции fun, и, тем самым, ускорить итерационный процесс. Подключение якобиана предусматривает два момента. Во-первых, среди входных параметров при обращении к функции fsolve должно быть соответствующее указание типа optimset( ■ jacobian', 'on*). Во-вторых, операторы для вычисления якобиана должны входить в определение функции fun, которая в данном случае должна возвращать два выходных аргумента. г""?"""?""""""""''""""" :"" ■-■■■ '""'■ "\v:;""^s^"o4j:^;5V'"?'""""™s№-""W'";4i;''"T""^vv'^'"""v^S^:k*''1£™^^"«: | Пример15-12: Вычисление якобиана поч^_{ши,™чес|мм;формулам^^^^^В-^^ function [F,J] = fun(x) Г = ... % вычисление вектора или матрицы системы if nargout > 1 % два выходных значения J = ... % вычисление якобиана как функции от х end В рассматриваемом примере якобиан представляет собой матрицу 2X2, образованную частными производными от yi и уз по xi и хг: ЭУ1 ЭУ1 Эх5 Эх2 ЭУ; ЭУ2 Эх: Эх. Добавим к функции funsc формулы для вычисления якобиана: function [у,j] = funscj(х) y=[x(l)+x(2)-sin(pi*x<l)>; x(l)-x(2)-cos(pi*x{2))]; if nargout>l j=[l-pi*cos(pi*x(l) 1; 1 -l+pi*sin(pi*K(2))]; end Зададим x0=[l;0.5] и выясним, насколько помогает наличие формул вычисления якобиана: » [х,f,e_flag,inform] = ... fsolve(@funscj,[1;0.5],optimset('Jacobian','on'))
606 Глава 15 Optimization terminated successfully: First-order optimality is less than options.TolFun. x = 0.5000 0.5000 f = 1.0e-008 * 0.1653 g.oooo e_flag = 1 inform = iterations: 7 funcCount: 7 algorithm: 'trust-region dogleg' firstorderopt: 1.6525e-009 По сравнению с предыдущим запуском для нахождения корня с такой же точностью потребовались те же 7 итераций, но количество обращений к функции fun уменьшилось в три раза. Справедливости ради следует отметить, что время работы функции за счет вычисления якобиана увеличилось примерно в два раза. Так что общий выигрыш по скорости нахождения корня составил примерно .50%. В теории линейных управляемых систем часто возникают матричные уравнения (пример 15.13). Они могут быть как линейными (уравнения Ляпунова и Сильвестра — см. разд. 13.7.3), так и нелинейными (уравнение Риккати — не путать с дифференциальным уравнением Риккати). ёПример 15.13. Метрйчйыв'уравйГеййя'.,^^Ё^?1^ .-. ■;**>&*.> .^,-^.-:¾¾¾.-, '-^щ^Ы Рассмотрим квадратное матричное уравнение вида ах2+вх+с=о, отвлекаясь от его происхождения. Определим функцию, аргументами которой кроме неизвестной матрицы х являются матрицы-коэффициенты а, в, С: function F= quadratic (X, А, В, С) F = А*Х*Х+В*Х+С; Зададим конкретные матрицы-коэффициенты А, в, с и стартовую матрицу хо: » А=еуе(2); % единичная матрица 2x2 » В=еуе(2); % единичная матрица 2x2 » О[-6, -5; 0, -6]; » X0=ones(2); % матрица 2x2, заполненная единицами
Нелинейные уравнения и оптимизация 607 и обратимся к функции f solve: » opt = optimset('Display','off'); » [XI, F, e_f lag]=fsolve (@quadratic, XO, opt, А, В, C) Обратите внимание на тот факт, что обращение к функции quadratic требует передачи ей не только аргумента х, но и еще трех дополнительных параметров — матриц а, в, с. В приведенном выше вызове функции f solve показано, как эти параметры должны быть переданы. В результате решения матричной системы уравнений получим следующие результаты: XI = 2.0000 -0.0000 F = 1.0е-009 * 0.3961 -0.2319 е flag = 1 1. 2. -0. 0. .0000 .0000 .6771 .3961 Вообще говоря, матрица xi=[2 1,-0 2] является точным решением нашего матричного уравнения. Однако f solve нашла приближенное решение, в чем можно убедиться, выдав большее количество значащих цифр: » format long » XI XI = 2.00000000008849 0.99999999982918 -0.00000000004637 2.00000000008849 Именно этим и объясняется ненулевая невязка f в найденной точке. Задав другую стартовую матрицу хо=-2*еуе(2), найдем второе решение квадратного матричного уравнения: XI = -3.0000 -1.0000 0 -3.0000 F = 1.0е-013 * 0 0.3730 0 0 ..e_f lag = 1
608 Глава 15 Как и в примере 15.10, не всякая стартовая матрица приводит к настоящему решению: для xo=-ones (2) получим: XI - -0.5314 -79.6478 -0.0784 -0.5314 F = -0.0010 -0.0008 0.0049 -0.0010 e_flag = 0 И довольно большая невязка f, и значение признака e_flag=o свидетельствуют о том, что найденное "решение" не является корнем нашего уравнения. Итерационный процесс был прерван в связи с превышением максимального количества итераций или обращений к функции quadratic. Установить более точную причину позволяет анализ одного из полей структуры, которую можно получить в качестве выходного параметра: » [XI,F,e_flag, out]=fsolve (Squadratic,X0, opt,А,В,C) XI = -0.5314 -79.6478 -0.0784 -0.5314 F = -0.0010 -0.0008 0.0049 -0.0010 e_flag = 0 out = iterations: 82 funcCount.: 402 algorithm: 'trust-region dogleg1 firstorderopt: 0.1514 Значение поля out.funccount свидетельствует о том, что превышено максимально допустимое количество обращений к функции. Рассмотрим пример 15.14. I. Пример 15.14; Поиск корней модуля полинома, ■-&&■?•.— " "Vv-V «fe»u* , ""■■ г- 1 В теории полиномов рассматривается вещественная функция комплексного аргумента — модуль полинома. Она, естественно, равна о в тех точках комплексной плоскости, которые являются корнями полинома. Рассмотрим
Нелинейные уравнения и оптимизация 609 комплексный полином w=z3+z, корнями которого ЯВЛЯЮТСЯ zi,3=±i И z2=0. Построим функцию — модуль этого полинома, в которой комплексный аргумент z представлен как вещественный вектор х[1:2]: function у = abspoly(x) z = complex(х(1),х (2)) ; w = z."3+z; у = abs(w); Попробуем с помощью функции fsolve найти решение нелинейной системы из одного уравнения с двумя неизвестными, задавая разные начальные точки: » xl=-0.5; х2=1.5; x0=[xl;x2]; » options=optimset('Display','off ) ; » [x,f,e_flag] = fsolve(@abspoly,xO,options) При первом же запуске функция fsolve выдает предупреждение о том, что метод "trust-region dogleg" не умеет решать неквадратную систему уравнений, поэтому она переключается на метод Гаусса—Ньютона: Warning: Default trust-region dogleg method of FSOLVE cannot handle non-square systems; switching to Gauss-Newton method. (Type "warning off Optimization:fsolve:NonSquareSystem" to suppress this warning.) Вывод текста предупреждения можно подавить, если предварительно выполнить команду: » warning off Optimization:fsolve:NonSquareSystem Результаты трех пробных запусков приведены в табл. 15.2. Таблица 15.2 № 1 2 3 хО xl -0.5 1 0.5 х2 1.5 0.5 -1.5 X х(1) -0.0019 0.4860 е-008 0.0019 х(2) 1.0013 -0.2634 е-008 -1.0013 fz 0.0046 3.6l.4 4e-0O9 0.0046 В первом и третьем случае невязка не очень мала. По дополнительной информации можно обнаружить, что процесс поиска корней был прерван (e_fiag=o) после 33 итераций и 202 обращений к функции. Во втором случае (e_fiag=i) для нахождения достаточно хорошего приближения к решению потребовалось всего 5 итераций и 28 обращений к функции. На рис. 15.3
610 Глава 15 представлены линии уровня функции abs(w) и три найденных решения вместе со стартовыми точками. Получено это изображение с помощью программы progl5_2.m (пример 15.15). Рис. 15.3. Нули комплексного полинома w=z3+z шштшшштшшмшшмшшвштш function ргод15_2 h=0.1; X0=-1.5:h:1.5; Y0=-2:h:2; [X Y]=meshgrid(XO,YO); s=size(X); for i = l:s(l) for j = 1:3(2) Z(i,j) = abspoly([X(i,j); Y(i,j>]>; end end M=max(max(Z)); v=0:0.2:l; V=1:M; contour(X,Y,Z,[v VI,'-r'); hold on; axis equal; grid off;
Нелинейные уравнения и оптимизация 611 xlabel('xl'); ylabel(•х2•); title('Решение нелинейного уравнения','Font-Name','Courier'); xlx2=[-0.5,1.5,1,0.5,0.5,-1.5]; options=optimset ('Display', 'off ) ; for j=l:3 xl=xlx2<2*j-l); x2=xlx2(2*j ) ; line(xl,x2, 'Marker', '.', 'MarkerSize', 10); [x,Л,e_flag,inform] = fsolve(@abspoly,[xl;x2], options) line(x(l),x{2), 'Marker', '.', 'MarkerSize', 20); plot([xl x(l)], [x2 x(2>], 'k-'); end 15.3. Минимизация унимодальной функции одной переменной Функция одного переменного y=f (х) называется унимодальной на отрезке [а, ь], если имеется единственное значение х0е[а, ь] такое, что: П f (хо) — минимум f (х) на [а, ь]; О f (х) строго убывает при х<хп; □ f(x) строго возрастает при х>хо. Для отыскания минимума унимодальной функции на заданном отрезке (пример 15.16) используется функция fminbnd. Алгоритм, реализованный ею, представляет собой комбинацию метода золотого сечения и обратной параболической интерполяции. В простейшем варианте вызова кроме указателя на минимизируемую функцию fun задаются начало и конец интервала Поиска: x=fminbnd(fun,a,b). » х=йт.пЬп<ЗГхЛ3-2*х',0,2) х = 0.8165 Рассмотрим пример 15.17. График функции y=fun(x)=3x4-4x3-i2xz представлен на рис. 15.4. На каждом из интервалов [-2, о] и [о, з] эта функция унимодальна. Для нахождения ее минимумов на указанных интервалах и построения графика с выделением точек минимума использована программа progl5_3.m.
612 Глава 15 ^:..-.,^.,^.^.,,^..^,................. Пример 15.17;'Прйе1с:мин'ймумрв KOHkpew ШШШШ>Ш** function progl5_3 хх=-2:0.1:3; yy=fun(xx); plot (хх, уу, 'к-') hold on; grid; xlabel('x'); ylabel('y'); [x,f]=fminbnd<Gfun,-2,0) line(x,f, 'Marker', '.', 'MarkerSize', 20); [x,f]=fminbnd(@fun,0,3) line(x, f, 'Marker', '.', 'MarkerSize', 20); function y=fun(x) у=3+х.л4-<3*х.л3-12*х.л2; 40 30 20 10 ^ 0 -10 -20 -30 -40, -л - \ ■ ■ ■ >. Sfi, -1 о 1 ■^ ^\ ^ i -1 '• X \ / v_/ , 2 - 1 /- /- / - / - - .i '. 1Й'- .. л , i 3 -., Рис. 15.4. Поиск минимума унимодальной функции Запуск этой программы дает следующие результаты: X = -1.0000 f = -5.0000 х = 2.0000 f = -32.0000
Нелинейные уравнения и оптимизация 613 На отрезке [-2, з] эта функция не является унимодальной, однако программа fitiinbnd находит один из минимумов (х=2.оооо) и не выдает никаких сообщений. Минимизируемая функиия может быть негладкой и даже разрывной (см. график на рис. 15.5): function prog!5_4 line ([-2,-eps],[g(-2),g(-eps)]); hold on; grid off; line{[eps,2],[g (eps), g (2)]); xlabel('x'); ylabel('y'); [x,f]=fminbnd{@g,-2,2) line(x,f,'Marker','.','MarkerSize',20); function y=g(x) if x<=0 y=-x-l; else y=x+l; end '"'.. ? *' 2.5 X^2 1.5 Ul 1 0.5 0 , -0.5 -1, • 1 <«Л - \ \ I -1.5 - :¾ ■0.5 / ч ■o X — .-_. 0.5 m- . 1 1.5 Ы. 4s 2 Рис. 15.5. Минимум разрывной функции Если в определении целевой функции g заменить if х<=о у=-х-1 на if х<0 у=-х-1, вид графика и результат поиска минимума не изменятся, хотя, строго говоря, новая функция своего минимума не достигает, а лишь неог-
614 Глава 15 раниченно к нему приближается. Положение спасает приближенный характер всех вычислений. 15.4. Многомерная безусловная минимизация Минимизации функций посвящено большое количество работ, из которых в нашем списке приведены [51, 68]. Задача поиска минимума вещественной функции векторного аргумента y=f(x) называется безусловной, если на ее аргумент не наложено никаких ограничений. В противном случае, когда вектор х должен удовлетворять каким-то уравнениям и/или неравенствам, говорят об условной минимизации. В MATLAB имеется несколько функций, реализующих различные подходы к безусловной минимизации. 15.4.1. Функция fminsearch В одной из функций — fminsearch — используется так называемый алгоритм симплексного поиска, идея которого заключается в следующем. В окрестности стартовой точки n-мерпого пространства строится симплекс — (п+1) точка в общем положении (никакие 3 точки не лежат на одной прямой, никакие 4 не лежат в одной плоскости и т. д.). Целевая функция измеряется в этих точках и та точка, в которой значение функции максимально, отбрасывается, а вместо нее в симплекс по определенным правилам вставляется другая точка. Процесс завершается, когда диаметр симплекса становится меньше заданного порога. Целевая функция может быть негладкой и даже разрывной. Простейшая форма обращения к этой функции совпадает с ранее приводившимися: х = fminsearch(fun,хО) Рассмотрим пример непрерывной, но негладкой функции двух переменных y=fun(x)=3|xi|+|xz|, единственный минимум которой находится в начале координат. Обращение к функции fminsearch дает следующий результат: » [x,f] = fminsearch('3*abs(x(l))+abs(x(2))',[1;1]> х = 1.0е-004 * -0.1439 0.3565 f = 7.8809e-005
Нелинейные уравнения и оптимизация 615 Рассмотрим разрывную функцию двух переменных discont, единственный минимум которой находится в начале координат: function z=discont(x) if (х{1) > 0) s (х(2) >= 0) % квадрант 1 z = х(1)+2*х(2); elseif (х(1) <= 0) & (х{2) ■> 0) % квадрант 2 z = -2*х(1)+х(2); elseif (х(1) < 0) & (х{2) <= 0) % квадрант 3 z = -х(1)-2*х(2>; elseif (х(1) >= 0) & (х(2) < 0) % квадрант 4 z = 2*х(1)-х(2); elseif (х(1) = 0) | (х(2) = 0) % начало координат z = 0; end После обращения к функции fminsearch получены следующие результаты: » options=optimset('Display', "off ); » х0=[0.5; 0.1]; » [x,f,e_flag] = fminsearch(@discont,x0,options) x = 1.0e-003 * 0.0640 -0.1342 f = 2.6229e-004 e_flag = 1 Примерно такие же результаты получатся и при других значениях х0. Рассмотрим пример 15.18. Знаменитый банан Розенброка имеет вид: z - 100(x2-x12)2+(l-xi)2 Графически он представляет собой овраг с очень крутыми склонами, дно которого при "взгляде сверху" имеет форму параболы (рис. 15.6) и плавно спускается к точке минимума х=[1;1], в которой z=o. Ее линии уровня представляют собой изогнутые овалы (отсюда "банан"). Чтобы получить бо-
616 Глава 15 лее компактный рисунок, коэффициент 100 перед первым слагаемым заменим более скромным значением 5: function f = Rosenbrock(х) f = 5*(х(2)-х(1)Л2)Л2+(1-х(1))Л2; Рис. 15.6. Минимизация "банана" Для поиска минимума и построения линий уровня функции Розенброка (см. рис. 15.6) была использовапа программа progl5_5.m: function prog!5_5 Х0=-3:0.1:3; Y0=-2:0.1:5; [X Y]=meshgrid(X0,Y0) ; s=size(X); Z=zeros(s); for i = l:s(l) for j = l:s(2) Z(i,j) = Rosenbrock([X(i,j); Y(i,])]); end end axesCXlim', [-3 3] ,'Ylim', [-2 5] ) ; axis equal; grid off; hold on;
Нелинейные уравнения и оптимизация 617 v=l:2:10; V=10:4:20; contour(X,Y,Z,[v VJ); xlabel('xl'); ylabel('x2') x0=[-2; 2]; line(xO(l),x0(2),'Marker','.','MarkerSize',10); [x,f] = fminsearch('5*(x(2)-x{l)A2)"2+{l-x(l))^2,,xO) line (x (1), x (2), 'Marker', ' . ', 'Marker-Size',20) ; plot([xO(l),x(l)],[xD(2),x{2)],'k-'); colonaap copper Найденный минимум: X = 1.0000 1.0000 f = 1.81-61e-009 Функция fndnsearch подобно функциям решения нелинейных уравнений может возвращать дополнительные параметры — признак завершения работы, структуру с информацией о результатах поиска (пример 15.19). / \ Пример -15.19;Допрлнительнtie №араметрЯ|'Воаэращабмые*£)Аш^^1:^/.^гг!.'^ » х0=[-2;2]; » [х,f,e_flag,inform]= ... £minsearch('5*(x(2)-x(l)л2)л2+(1-х(1))л2' ,xQ) i x = 1.0000 1.0000 f = 1.8161e-Q09 e_flag = 1 inform = iterations: 61 funcCount: 115 algorithm: 'Nelder-Mead simplex direct search'
618 Глава 15 15.4.2. Функция fminunc В том случае, когда функция fun(x) является достаточно гладкой, для поиска ее минимума можно воспользоваться функцией fminunc. Идея поиска минимума с помощью производных принадлежит Коши и заключается в следующем: градиент функции fun(x) в любой точке х есть вектор д, направленный в сторону наибольшего локального увеличения функции fnn(x). Следовательно, для достижения минимума надо двигаться в направлении наискорейшего спуска -д. В более развитом варианте этого алгоритма используются также вторые производные, которые образуют так называемую матрицу Гессе (гессиан) н. При помощи формулы Тейлора строится локальная квадратичная аппроксимация целевой функции в окрестности текущей точки хк: Eun(xk+p) = fun(xk)+g}:,*p + р'*нк*р/2 Минимум выражения в правой части (если он существует) достигается при векторе смещения р, который удовлетворяет системе уравнений нк*р=-д*. Такой способ выбора направления называется методом Ньютона. Иногда на вектор смещения накладывается ограничение |р|<Д при специально подобранном Д — в этом случае говорят о методе доверительного интервала. Большинство форм обращения к функции fminunc, в которой реализованы оба эти метода, аналогично обращению к рассматривавшимся ранее функциям. В простейшем случае ее аргументами являются указатель на функцию fun и начальная точка: х = fminunc(8fun,x0) Для ускорения процесса поиска в функцию fun желательно включить формулы для вычисления градиента (это должно быть также оговорено в управляющих параметрах options). В противном случае функция fminunc выдает 11 редупреждение: Warning: Gradient must be provided for trust-region method; using line-seareh method instead. Это предупреждение не препятствует продолжению работы, т. к. градиент (и гессиан) могут быть построены в каждой точке численно. Рассмотрим пример 15.20. | Пример 15.20. Поиск минимума функции ^' ~. I.Vi'w .г ■'Sx.^ss^&sSv-! Путь имеется функция: f = *l + *2 - 3*1Х2
Нелинейные уравнения и оптимизация - 619 Ее линия уровня при f=o представляет собой известную в геометрии кривую — декартов лист. Подключим к профамме вычисления значения функции операторы для нахождения градиента g и гессиана н (см. текст функции Descartes). Сообщим об этом в списке управляющих параметров для функций минимизации: options=optimset('Display','final','GradObj', 'on', 'Hessian', 'on'); Значение параметра Dispiay=final означает, что все промежуточные выдачи, кроме заключительной, блокируются. Возьмем стартовую точку для поиска минимума хО=[2; 2]. Обращения к функции fminunc выполним в форме, позволяющей получить на выходе также значения градиента й гессиана. [х,f1,e_f lag, out,grad,hes]=fminunc(@ Descartes,xO, options) Построение линий уровня, фиксация начальной точки и найденного минимума (рис. 15.7) выполнены с помощью программы progl5_6.ni: function ргод15_б axes{'Xlim',[-1.5 2.5],'Ylim',[-1.5 2.5]); axis equal; grid off; hold on; xlabel('xl'); ylabel('x2'); cplormap copper X0=-1.5:0.05:2.5; [X Y]=4tieshgrid(X0) ; s=size(X); Z=zeros(s); for i = l:s(l) for j = l:s(2) Z(i,j) = Descartes{[X(i,j>; Y(i,j)]); end end V=-0.8:0.2:l; contour(X,Y,Z,V); options = ... optimset('Display','final','GradObj','on','Hessian', 'onM; xO=[2; 2]; Iine(x0.(l),x0(2) , 'Marker', '.', 'MarkerSize', 10) ; [x,fl,e_flag,out,grad,hes] = fminunc(@Descartes,xO,options) line(x(l),x(2),'Marker','.','MarkerSize',20); plot([xO(l),x(l)], [x0(.2),x(2)],'k-');
620 Глава 15 function [f,g,H] = Descartes(x) f = х(1)л3+х(2)л3-3*х(1>*х(2>; if nargout > 1 g = [ЗМх(1)л2-х(2П; 3* (х(2)л2-х(1) ) ] ; end if nargout > 2 H = [6*x(l) -3; -3 6*x(2)]; end end Рис. 15.7. Декартов лист Результаты работы программы progl5_6.m приведены ниже: »■ Optimization terminated successfully: First-order optimality less than OPTIONS.TolFun, and nc negative/zero curvature detected x — 1.0000 1.0000
Нелинейные уравнения и оптимизация 621 fl = -1 e_flag = 1 out = iterations: 6 funcCount: 6 cgiterations: 5 firstorderopt: 6.9849e-010 algorithm: 'large-scale: trust-region Newton' grad = 1.0e-0.09 * 0.6985 0.6985 hes = 6.0000 -3.0000 -3.0000 6.0000 В найденной точке (x=[i, ll) градиент близок к нулю, а гессиан — положительно определен, что свидетельствует об успешном решении задачи. Рассмотрим пример 15.21. .Пример 15.21. Практическое приложение; ?>^^^\*^«^^- ^^=1¾¾¾^^^ i: ^1 Рассмотрим задачу об управлении роботом-манипулятором в упрощенной двумерной постановке. Она формулируется так: робот представляет собой многозвенный механизм, состоящий из нескольких стержней. Один конец первого стержня закреплен в шарнире и может в нем поворачиваться, остальные стержни соединены последовательно также с помощью шарниров. На конце последнего стержня находится рабочий орган — cxeatn. На рис. 15.8 стержни изображены в виде отрезков, шарниры в виде кружочков, закрепленный шарнир — кружочек с треугольником, схват — маленький квадрат. На рисунке также обозначены углы qi, q2, q3, являющиеся обобщенными координатами манипулятора. Введем декартову систему координат Ох\х2, начало которой совпадает с неподвижным шарниром, ось Ох\ направлена вправо, ось Ох2 — вверх.
622 Глава 15 Рис. 15.8. Манипулятор Координаты схвата выражаются через длины стержней и, 12, 13 и углы qi, <q2, q3: xj^ll^cos(ql)+12+COS(ql+q2)+13*cos(ql+q2+q3) X2=ll*sin(ql)+12*sin(ql+q2)+13*srn(ql+q2+q3) Вектор x=[xi,- x2] вычисляет функция coordciamp, построенная на основе этих формул: function x=coord_clamp(q,1) Q=cumsum(q); x=[sum(l. *cos (Q}) ; sum(l.*sin(Q}') ] ; Требуемое положение схвата задается вектором хс, целью управления является минимизация нормы разности х-хс: function d=discrepancy(q,1,хс) ■x=coor.d_clamp (q, 1) ; d=norm(x-xc) ; Зададим начальный вектор углов qo, вектор длин стержней 1, требуемое положение схвата хс и обратимся к функции fminunc: » с0=[0.7 -1 0.5]; » 1=[5 5 5]; » хс=[12; 01; >> [q,f l=fminimc (Sdiscrepancy,q0, [J,l,xc.) Optimization terminated successfully: Search direction less than 2*options.TolX q = 0.6650 -1.576.8. 0.6036
Нелинейные уравнения и оптимизаций 623 f = 4.6500е-007 Весьма малая величина невязки f легко объяснима: для схвата достижима любая точка плоскости, отстоящая от начала координат на расстояние, не превышающее сумму длин стержней (в примере требуемое расстояние 12, сумма длин 15). Начальное и конечное положения манипулятора, представленные на рис. 15.9, получены с помощью программы progl5_7.m: function progl5_7 axes('Xlim\ [-1 15], ' Ylim', [-1 10]); axis equal; grid on; hold on; 1=[5 5 5]; xc=[12; 0); qlnit=[0.7 -1 0.5]; [XInit,YInit]=hinges(qlnit,1); plot(XInit,YInit,* k:'); qCptim=[0.8650 -1.5768 0.6036]; [XOptim,YOptim]=hinges(qOptim,1); plot(XOptim,YOptim,'k-•,'LineWidth', 2) ; plot (10],[-0.3],'k~\'MarkerSize',15); plot(XInit(1:3),YInit(1:3),'ко'); plot ([XInit(1)], [YInit(4)],'ks', 'MarkerSize',15}; plot(XOptimfl:3),Y0ptim(l:3),'ко'); plot([XOptim(4)],[YOptim(4)],'ks','MarkerSize',15); xlabel('xl'); ylabel(■x2 *); hL=legend('Начальное','Конечное'); set(hL,'FontName', 'Courier') title ('Два положения манипулятора','FontName','Courier'); function [X,Y]=hinges (q, 1) Q=cumsum(q); x=l.*cos(Q); y=l.+sin(Q_) ; x-[0 x]; y=[0 y]; X=cumsum (x); Y=cumsurn (у) ; Функция hinges (шарниры) вычисляет положения всех шарниров при заданных значениях углов и длин стержней.
624 Глава 15 * - в »V:A,£"r-"" #'&£ 6 »:i--o«iSa - о --■ -2 Два положения манипулятора Начальное Конечное Г —V,- тч"-- --<&=*- ■ ..- —□ ]. 5 10 ■ 15 xi Рис. 15.9. Начальное и оптимальное положения манипулятора 15.4.3. Функция Isqnonlin Функция isqnonlin применяется в тех случаях, когда целевая функция имеет вид F=Sf i2. В этом случае градиент g и гессиан н функции f выражаются через якобиан j вектор-функции f=.[fi, f2,..., fm] ': g=J'*f; H=J'*J+R; Остаточный член R включает вторые производные от F, но в окрестности минимума им обычно пренебрегают по сравнению с j'*j. Это дает возможность не вычислять вторые производные, что значительно ускоряет работу по сравнению с общим случаем. Поэтому для поиска минимума целевой функции рассматриваемого вида (сумма квадратов) нецелесообразно использовать функцию fminunc. Система уравнений для отыскания вектора сдвига н*р=-д при замене н на J'*j превращается в j'*J*p=-j'*f. Этот способ называется методом Гаусса- Ньютона. В методе Левенберга—Марквардта матрица j'*j в левой части системы уравнений заменяется на j1 *j+A*i, где i — единичная матрица, а X — некоторое неотрицательное число. Для вектора смещения задается офаничение |р|<Д, где значения Д и X взаимосвязаны.
Нелинейные уравнения и оптимизация 625 В функции lsqnonlin применяются оба метола: Гаусса—Ньютона и Левен- берга—М ар квардта. В обращении x=isqnoniin<fun,xO) минимизируется сумма квадратов компонент вектора-столбца, который вырабатывает функция fun (это может быть также матрица). Второй аргумент хО как всегда, стартовая точка для поиска. Рассмотрим пример 15.22. Функция Розенброка представляет собой сумму двух квадратов, поэтому для ее минимизации можно применить lsqnonlin. Определим функцию: function f = Rosenbrock2(х) f = [sqrt(5)*(x(2)-x{l)-2); l-x(l)]; Зададим начальное приближение хО и обратимся к функции lsqnonlin: » хО =[-2; 2]; » х = lsqnonlin(GRosenbrock2,xO) х = 1.0000 1.0000 Рассмотрим пример 15.23. I Пример 15.23^Псевяорешение несовместной системы линейных уравнений •- Для несовместной системы линейных уравнений а*х=ь можно поставить задачу нахождения вектора х, дающего минимальную сумму квадратов компонент вектора невязки г=а*х-ь. Этот вектор называют псевдорешением (в случае совместной системы псевдорешение совпадает с обычным решением). Рассмотрим конкретную систему: function fr=r(x) A=[l 1; 1 -1; 2 1]; Ь=[2;0;2]; fr=A*x-b; Зададим начальный вектор для поиска хО и обратимся к функции lsqnonlin: » х0=[0;0]; » х = lsqnonlin(@г,х0)
626 Глава 15 Q.7143 .0.8571 (~ Замечание ^ Задание матрицы а и вектора Ь непосредственно внутри функции — не самое оптимальное решение (для другой матрицы и/или вектора придется переписывать функцию). Предпочтительно сделать эти объекты дополнительными аргументами функции г, включив их также в обращение к lsqnpnlin. Тогда определение функции г станет гораздо лаконичнее (и универсальнее): function fr=r(x,A,b) fr=A*x-b; Конкретные матрицу а и вектор ь зададим в качестве дополнительных входных аргументов функции lsqnonlin: х = lsqnonlin(@r,x0, [],[], П,A,b) Пустые матрицы [] замешают аргументы, о которых речь пойдет дальше. ("" Замечание ^ Рассмотренный пример носит чисто иллюстративный характер— искомое псевдорешение можно получить гораздо проще, выполнив команду х=А\Ь. Рассмотрим пример 15.24. 'i'ij'i/i.i'i^ii-it^yi Некоторые химические процессы описываются уравнением y=a+be"c\ Неизвестные коэффициенты а, ь, с обычно определяют по экспериментальным данным, стараясь минимизировать среднеквадратичное отклонение теоретической кривой от наблюдаемых значений: Z(y-<a+be-c*})2 Введем вектор р, компонентами которого являются параметры модели: а=р(1), Ь=р(2), с=р(3) Определим функцию expmod(p,x,y): function q=expmod(p,x,y) q=y-(p(l)+p(2)*exp(-p(3}*x)>; Зададим векторы-столбцы х и у, выберем начальное приближение рО и обратимся К функции lsqnonlin: »х= [ 0.4; 1.4; 5.4; 19.5; 48.2; 95.9]; » у= [51.6; 53.4; 20.0; -4.2; -3.0; -4.8];
Нелинейные уравнения и оптимизация 627 » рО=[0; 0; 0] » р = isqnoniin(@expmod, рО,[],[],[),х, у) Maximum number of function evaluations exceeded; increase options.MaxFunEvals P = ■ 8.3312 9.3646 0.0711 Поместив в левую часть обращения конструкцию [р, resnorm]=..., кроме основного результата р получим сумму квадратов разностей: resnorm = 3:.0609е+003 Результат не слишком ободряющий, да и сплошной график на рис. 15.10 довольно далек от экспериментальных точек. Можно было бы попытаться достичь большей точности, увеличив максимальное количество обращений к функции (по умолчанию функция isqnoniin перестает работать, когда количество обращений достигает 300): » options=optimset('MaxFunEvals',600); » [р,resnorm] = Isqnoniin(@expmod,p0, [], [J,options, x,y) P = 6.6477 10.0967 0.0860 resnorm = 2.9463e+003 Значения коэффициентов а, ь, с получились несколько иными, но квадратичное отклонение осталось достаточно большим. Но ведь метод isqnoniin не сообщил, что решение найдено. Останов произошел из-за нарушения некоторого условия (превышено количество обращений к функции). Вполне возможно, что более серьезной причиной послужил неудачный выбор начального приближения. Можно ли достичь хорошего результата с помощью функции isqnoniin? Попробуем повторно обратиться к ней, задав в качестве начального приближения нехорошее решение: » р0=р; >> [р,resnorm] = Isqnonlin(@expmod,p0,[],[],[],х,у) Maximum number of function evaluations exceeded; increase options.MaxFunEvals
628 Глава 15 Р = 10.7401 19.6528 0.1151 resnorm = 1.8844е+003 "Решение" улучшилось, но причина прекращения итераций осталась прежней. А что будет, если повторить попытку с новой начальной точки: » р0=р; » [р,resnorm] = lsqnonlin(Gexpmod,pO, [],[],[],х,у) Optimization terminated successfully: Relative function value changing by less than OPTIONS.TolFun P = -4.8524 65.2656 0.1657 resnorm = 74.0366 На этот раз оптимизация завершена успешно, да и невязка уменьшилась почти в 30 раз. Если бы мы начинали поиск оптимума не с нулевой точки, а, например, из точки [ю, ю, 10J, то решение было бы найдено с первой попытки. Для сравнения, минимум функции ехрпюаг, которая вычисляет сумму квадратов компонентов функции expmod, был найден с помощью функции fminsearch и совпал с приведенным выше результатом. График "хорошего" приближения нанесен на рис. 15.10 черными точками, и он вполне удовлетворительно аппроксимирует экспериментальные данные (рисунок получен с помощью программы progl0_8). function p.rogl5_8 axes('XIim\ [-20 100],'Ylim',[-10 601); grid on; hold on; x= [0.4; 1.4; 5.4; 19.5; 48.2; 95.9]; y= [51.6; 53.4; 20.0; -4.2; -3.0; -4.6]; plot(x,y,'ko'); .options=optimset('MaxFunEvals', 600} ; p0=[0;0;0]; [p,resnorm] = Isqnonlin{@expmod,p0, [],[],options,x,y) xp = -10:100; yp = p(l}+p(2)*exp(-p<3)*xp);
Нелинейные уравнения и оптимизация 629 plot(xp,ур,'к-'),- [q,f] = fminsearch(@expmod2,p0,options,х,у) xq = 10:2:100; yq = q(l)+q(2}*exp(-q(3)*xq); plot(xq,yq,'k.'}; title ('Две экспоненциальные модели.','FontName','Courier') xlabeK'x'}; ylabel('y') hL=legend('данные','1-я модель','2-я модель', 0); set(hL,'FontName','Courier') function q2=expmod2(p,x,y) q=y-(p(l)+p(2)*exp(-p(3)*x)); q2=sum(q.A2) ; Две экспоненциальные модели' 60 50 40 30 г* 20. 10 0 "'-20 0 20 40 60 8D 100* х Рис. 15.10. Аналитическое приближение экспериментальных данных Заметим, что полиномиальная аппроксимация с тремя коэффициентами (у=ах2+Ьх+с) бьша бы гораздо хуже, а увеличивать число коэффициентов модели при 6 наблюдениях нецелесообразно. 15.4.4. Функция fminimax К функции lsqnonlin идейно близка функция fminimax: в обеих скалярная целевая функция не задается непосредственно в обращении, а формируется путем свертки из компонентов вектора (или матрицы), передаваемого функ- L..J I* i Л i • 1 т*—' " Л 1 ■ * 1 ' "J Ч-Т--- -- 1 1 О данные 1-я модель ■ 2-я модель j >*
630 Глава 15 ции. В isqnoniin минимизируется сумма квадратов компонентов, а в fminimax — максимальная составляющая (по желанию пользователя — максимальная по абсолютной величине). Алгоритм, реализованный в fminimax, многократно использует квадратичное программирование, а также поиск с помощью градиента и гессиана. Простейшая форма обращения к fminimax аналогична обращениям к предыдущим функциям поиска минимума: х = fminimax(fun,хО) Рассмотрим пример 15.25. :.'..; Л -..:......:-..:... A.^.-vS.v...-......-..: :.'. .-. ...v;.:..:;:v.i.".;K«.^S.-»^ Найдем минимум функции max(-xi,xi,-x2,x2). Для этого определим вектор-функцию plusminus: function f = plusminus(х) f(1)= -x(l); f(2)= x(l); f(3)= x(2); , f(4)= -x(2); Зададим начальную точку xo и обратимся к функции fminimax: » xD=[l; И; » х = fminimax(@plusminus,xO) Optimization terminated successfully: Search direction less than 2*options.TolX and maximum constraint violation is less than options.TolCon Active Constraints: 1 2 3 x = 1.0e-024 * 0 0.8272 Найденный минимум достигается в точке, очень близкой к началу координат. Смысл последнего сообщения (Active Constraints. . .) состоит В том, что найденная точка является пересечением трех поверхностей: f(i)=o; f (2)=о; f (3)=о (в данном случае это плоскости). Точка принадлежит и четвертой плоскости f (4)=0, но в трехмерном пространстве для идентифика-
Нелинейные уравнения и оптимизация 631 ции точки достаточно трех поверхностей, и программа выбирает первые попавшиеся. С помощью функции fminimax можно построить так называемую равномерную или чебышевскую аппроксимацию табличных данных. Напомним, что если на числовой оси заданы точки xi<x2<... <хп и значения yi, у2, ..., уг, где каждое ух — вещественное число, соответствующее точке хь то задача одномерной аппроксимации состоит в том, чтобы построить просто вычисляемую функцию y=f (х,а), аппроксимирующую эти данные. Здесь а — один или несколько параметров, выделяющих конкретную функцию в некотором классе (например, вектор коэффициентов полинома). Эти параметры выбираются так, чтобы минимизировать разницу между заданными значениями ys и вычисленными при помощи функции y=f (xifa). Известны два основных подхода к построению модели — метод наименьших квадратов (см. разд. 13.1) и равномерная аппроксимация. В первом случае ищется минимум 2(yi-f (xifa) )2, ВО ВТОРОМ — МИНИМУМ велИЧИНЫ max |yi-f(xi, а) |. Рассмотрим пример 15.26. ['ДЗ§|йШ|ЙШ^Ж аппроксимация ПреДПОЛОЖИМ, есть Табличные данные х=[-2;-1;0;1;2], у=[0;0;1;0;0]. В гл. 13 (см. пример 13.2) с помощью функции polyf it был построен полином степени 2, наилучшим образом приближающий эти данные в смысле наименьших квадратов. Его коэффициенты р= [-0.1429 о.оооо 0.48571. Построим теперь полином той же степени, дающий равномерную аппроксимацию этих данных. Определим функцию, основным аргументом которой яапяется неизвестный вектор коэффициентов с, а данные х, у — дополнительными аргументами. function u=unifonrt(с,х,у) и=аЬз<у-(с(1)*хЛ2+с(2)*х+с(3}))); Зададим начальный вектор со и обратимся к функции fminmax (пустые операнды в этом обращении заменяют аргументы, о которых речь пойдет в разд. 15.5): » х=[-2;-1;0;1;2]; » у=[0;0;1;0;01; » сО = [0;0;0]; » с = fminimax (^uniform, сО, [], [] Д], [] Д] Д] ДЬ П,х,у) Active Constraints: 1 2 3 4 21 Зак.899 ....:.:.4>j~».w..w....-..."...:..........r
632 Глава 15 с - -0.2500 -0.0000 0.6250 По этим коэффициентам был с помощью программы progl5_9.m построен график полинома, равномерно приближающего данные (рис. 15.11). '." 1-5 1 - С0* 0 >г -.1 -1.5 ■ -2. -.■ '■"' '" • • ш т * * Л 3 . . jr * * • ш -2 Дв& полиномиальные О "•••. J&- модели •■'itis-^.-- ■■■■■■■ О данные мин.квадраты • равномерная i&'^r' -¾¾ Щ*; • ° ° *>^ Щ. • ^ " -**""" ■ Л • • Г- * ^ -1 о' 1 '■.,:•, 2 ,-.-. з Рис. 15.11. Полиномиальная аппроксимация Для сравнения на том же рисунке приведен график полинома, полученного по методу наименьших квадратов. function ргод15_9 axes('Xlira', [-3 3],'Ylira',[-2 1.5]}; hold on; x=[-2;-l;0;l;2]; y=[0;0;l;0;0]; c0=[0;0;0]; [c, f,maxf, e_f lag, inform] = ... fminimax(@unifonn,cO, [],[|,[],I1i[)f[]i[], П,х,у) p=polyfit(x,y,2) xx = -3:0.1:3; plot(x,y,'ko',xx,polyval(p,xx),'k-',xx,polyval(c,xx),'k.'}
Нелинейные уравнения и оптимизация 633 title('Две полиномиальные модели','FontName','Courier') xlabel('x'); ylabel('y') hL=legend('данные','мин. квадраты','равномерная', 0) ; set(hL,'FontName','Courier'} Выполнение функции progl5_9.m помимо вывода графиков, приведенных на рис. 15.11, сопровождается следующими результатами: » ргод15_9 Optimization terminated successfully: Search direction less than 2*options.TolX and maximum constraint violation is less than options.To1Con Active Constraints: 1 2 3 4 с = -0.2500 -0.0000 0.6250 f = 0.3750 0.3750 0.3750 0.3750 0.3750 maxf = 0.3750 e_flag = 1 inform = iterations: 4 funcCount: 29 stepsize: 1 algorithm: 'minimax SQP, Quasi-Newton, line_search' f irstorderopt: [] cgiterations: [] P ~ -0,1429 0.0000 0.4857
634 Глава 15 При обращении к функции fminimax можно задать управляющий параметр MinAbsMax, который заменяет компоненты вектора-функции их абсолютными величинами (однако при выводе значений компонентов их знаки сохраняются). В предыдущем примере за счет этого управляющего параметра можно было бы опустить abs в определении функции uniform. Рассмотрим трехкомпонентную вектор-функцию одной переменной (пример 15.27). ."■"■ ■■■■■"".?'■" -.-v.".. .• • ...v . .............,^. :;Яример 15.27. Поиск минимума максимальной компоненты вектора-функции ,., \ function f=threefun(t) f (1,: )=-1.5*t,- f(2, :)=2*t-t.-2; f(3,:>=t-6; С помощью fminimax найдем минимум максимальной из ее компонент и представим на графике (рис. 15.12) полученные результаты. function progl5_10 tt=-3:0.1:4,- f f=threef un (t £) ; hold on; grid off; title('fminimax без MinAbsMax','ForitName','Courier') xlabeK't'}; ylabel('f ),- plot(tt,ff(1,:),'k:'); plot(tt,ff(2,:),'k:'); plOt(tt,ff(3,:),'k:'); mf=zeros(size(tt)); for i=l: length(tt) ft =threefun(tt(i)); mf(i)=max([ft(l,:), ft(2,:), ft(3,:)]); end plot(tt,mf,'k-'}; graf(-l); graf(3.5),- function f=threefun(t) f (1,:)=-1.5*t; f (2,:}=2*t-t.~2; f{3,:)=t-6;
Нелинейные уравнения и оптимизация 635 function giraf(tO) options - []; line(tO,0, 'Marker', '.', 'MarkerSize', 10); [t,fval,maxfval] = ... fminimax(Gthree£un,tO,[], [J, [], [], [], [], [], options) line(t,maxfval,'Marker','.','MarkerSize', 20); plot ([tO t], [0 maxfval],'k-'); function f=threefun(t) f(l,:)=-1.5*t; f(2,:}=2*t-t.A2; f (3,:) =t-6; % Решение для t0=-l Active Constraints: 1 2 t = % найденный минимум 4.5174e-017 fval = % значения компонентов функции в найденной точке -0.0000 0.0000 -6.0000 maxfval = -б.7761е-017 S Решение для t0=3.5 Active Constraints: 2 3 t- = % найденный минимум 3.0000 fval = % значения компонентов функции в найденной точке -4.5000 -3.0000. -3.0000 irtaxfval = -3.0000
636 Глава 15 Рис. 15.12. Минимум максимальной компоненты Рассмотрим пример 15.28. ^Пример ;Щ ' >-А'" • н* Продемонстрируем влияние свойства MinAbsMax на результат работы функции fminir.ax. Для этого в программе progl5_10 подменим значение параметра options. Значением управляющего параметра MinAbsMax является количество составляющих вектора-функции, заменяемых абсолютными величинами: options = optimset('MinAbsMax',3} Дополнительно придется воспользоваться модулями составляющих функции threefun при обращении к функции plot: plot(tt,abs(ff(1,:}), 'k:'}; plot(tt,abs(ff(2, :)), 'k: '}; plot(tt,abs(ff(3, :}), 'k:") ; Результат работы модифицированной таким образом функции minmaxtstl представлен на рис. 15.13. В этом варианте для обеих начальных точек to=-i и to=3.5 функция fminmax возвращает одну и ту же точку, в которой достигается минимум: Active Constraints: 2 3
Нелинейные уравнения и оптимизация 637 t = % найденный минимум 2.4000 fval = % значения компонент функции в найденной точке -3.6000 -0.9600 -3.6000 maxfval = 3.6000 Рис.15.13. Минимизация модулей функции 15.5. Условная минимизация Если при поиске минимума вещественной функции векторного аргумента y=f (х) на аргумент наложены те или иные ограничения в виде уравнений и/или неравенств, говорят об условной минимизации. Основной метод решения таких задач основан на использовании множителей Лагранжа. Каждое неравенство вида д(х)<о превращается в уравнение g(x)+v2=o (слагаемое v2 заведомо нео'фицательно). Затем левая часть каждого уравнения добавляется к целевой функции с некоторым множителем, эти множители и величины v включаются в число переменных. Для модифицированной таким образом функции решается задача безусловной минимизации.
638 Глава 15 15.5.1. Функция fmincon Для решения задачи условной минимизации функции fun(x) при наличии линейных ограничений оптимизации а*х<Ь (а — матрица, ь — вектор) используется функция fmincon, обращение к которой требует задания начальной точки хо: х = fmincon)fun,хО,А,Ь) Функция fmincon допускает наложение дополнительных ограничений вида: П Aeq*x=bsq — линейные уравнения (Aeq — матрица, beq — вектор); □ ib<x<ub — ограничения на координаты (lb, ub — два вектора). И тогда простейшие варианты обращения к fmincon выглядят следующим образом: х = fmincon(fun,хО,A,b,Aeq, beq) х = fmincon(fun,хО,A,b,Aeq,beq,lb,ub) Еще одно нелинейное условие может быть задано с помощью двухкомпо- нентной функции [c,ceq]=nonlcon(x), для которой искомая точка минимума должна удовлетворять двум ограничениям: с(х)<о и ceq(x)=o. В этом случае к списку входных параметров добавляется указатель на функцию nonlcon: х = fmincon(fun,хО,A,b,Aeq,beq,lb,ub,nonlcon) Если какой-то из перечисленных выше входных параметров не используется, вместо него задается пустой аргумент ([]). Если отсутствуют ограничения на отдельные компоненты x(i) сверху или снизу, то соответствующие компоненты векторов ub и ib задаются как +°° (ub(i)=inf) или -» (ib(i)=-inf). Рассмотрим пример 15.29. [Пример 15.29. Минимум функции Розенброка в полуплоскости " Найдем минимум функции Розенброка при ограничении x-l-x2+4<o, задающем полуплоскость. Определим матрицу а=[1 -1], вектор ь=[-4], начальную точку х0= [-3,-4] (эта точка удовлетворяет ограничению) и обратимся к функции fmincon: » А=[1 -1] ; » Ь=[-4]; » х0=[-а,-4]; » х = fmincon('5*(x(2}-x{l)A2)'-2h(l-x(l))^2,rxO,A,b)
Нелинейные уравнения и оптимизация 639 Active Constraints: 1 х = 2.5431 6.5431 При более полной форме обращения [x,fvai]=fmincon(...) можно получить значение целевой функции в найденной точке: fval = 2.4098 Для другой начальной точки х0=[0;1] (эта точка не удовлетворяет ограничению) получим fvai=6.484i. в точке х= [-1.5311 -2.4 689]. Графические результаты двух этих попыток представлены на. рис. 15.14. Они получены с помощью, программы ros_tst.m: function ros_tst Х0=-5:0.1:3; Y0=0:0.1:7; [X Y]=meshgrid(X0,Y0); s=size(X); Z=zeros(s); for i = 1:S(1) for j = l:s(2) x = [X(i,j); Y(i,j)]; z = Rosenbrock(x); Z(i,j) = z; "end end V=l: 10; contour(X,Y,Z,V); hold on; grid off; xl=-5:5; x2=0:7; xlabel('xl'); ylabel(.'x2') plot ([-4 3], [0 7], "k-'l; x0=[-3; 4]; graf(xO) %#1 x0=[ 0; 1]; graftx0} %#2 function graf(xO) A=L1 -1); b=[-4'J; options=[];
640 Глава 15 line(xOd),х0(2), 'Marker', '.', 'MarkerSize', 10}; [x, fval] = fmincon(@Rosenbrock,xO,A,b) line(x(lj,x(2), 'Marker', '.', 'MarkerSize', 20); plot([xO(l),x(l}], [x0(2},x(2)],'k-'); function f = Rosenbrock(x) f = 5*(х(2)-х(1)л2)л2+(1- х(1))л2;х(1}}л2; Рис. 15.14. Минимум функции Розенброка Рассмотрим пример 15.30. (Пример 15.30. Минимум функции Розенброка внутри единичного круга 1\ -*А-? \ ; Найдем минимум функции Розенброка при ограничении (xi-i)2+(x2- -1)2<1, задающем внутренность единичного круга с центром в точке (1, д.). Определим функцию circleli: function [с, ceq] = circleli(х) с = (х(1)-1)Л2+(х(2)-1)Л2-1; ceq = [],-
Нелинейные уравнения и оптимизация 641 Зададим х0=[2;1] и обратимся к функции fmincon: х = йш.псоп{'5*(х(2)-х(1)л2)л2+(1-х(1))л2■,... хО, [],[], [],[], n,[],Gcirclell) No Active Constraints x = 0.9963 0.9926 Сообщение "No Active constraints" означает, что найденная точка не удовлетворяет ограничению, как равенству. При более полной форме обращения [х, fval]=fmincon.(...) функция возвратит значение целевой функции в найденной точке: fval = 1.4019е-005 Точное значение минимума равно нулю. Более полная форма обращения к функции fmincon позволяет передавать минимизируемой функции fun и функции ограничений nonicon кроме аргумента х список дополнительных параметров pi, Р2, ...: x=fmincon(fun,xO,A,b,Aeq,beq>ib,ub,nonicon,options,El,P2,...) Ускорение вычислительного процесса может быть достигнуто заданием формул вычисления градиента и/или гессиана (пример 15.31). |;,П|^ё^5.31^щи!1^^^.градиента и гессиана^ /-,,^ ^:^¾¾¾¾¾^¾¾^¾¾¾¾ Дополним функцию Розенброка вычислением градиента g и гессиана н: function [f,g,H] = Rosenbrock(х) f = 5Мх(2)-х(1)Л2}Л2+(1-х(1})Л2; if nargout > 1 g= [-20*(x(2)-x(l)*-2}*x(l)-2*(l-x(l)); 10* (x(2)-x(l) "2) ] ; end if nargout > 2 H= [20*(3*x(l)-x(2})+2 -20*x(l); -20*x(l) 10]; end Зададим x0= [-2,-2] и выполним команды: » options = ... optimset("Display','final','GradQbj','on','Hessian','on■),
642 Глава 15 » к = fmincon(GRosenbrock,хО, [], [], [], [], [], [], dcirclell,Options) No Active Constraints, x = 1.0000 i.oooo Наиболее полный список выходных параметров, возвращаемых функцией fmincon, представлен в следующем обращении: [х,fval,e_flag,inform,lambda,grad,hes] = fmincon(...} Кроме ранее упоминавшихся выходных аргументов здесь добавилась структура lambda, содержащая множители Лагранжа. Попытка выполнить последнее обращение к функции fmincon в наиболее полной форме приводит к выводу довольно большого объема полезной информации: » [х,fval,e_flag,inform,lambda,grad,hes]=... fmincon(@Rosenbrock,xO,[],[],[],[],[],[],@circlell,options) fval = % значение целевой функции в найденной точке 6.8910е-010 e_flag = % поиск завершен успешно 1 inform = iterations: 13 funcCount: 62 stepsize: 1 algorithm: 'medium-scale: SQP, Quasi-Newton, line-search' lambda = % информация о множителях Лагранжа; в данном случае она пустая, % поскольку найденная точка не удовлетворяет ограничению % как равенству lower: [2x1 double] upper: [2x1 double] eqlin: [1x0 double] eqnonlin: [1x0 double] ineqlin: [1x0 double] ineqnonlin: 0 grad = % градиент 1.0e-003 *
Нелинейные уравнения и оптимизация 643 0.2121 0.6299 hes = % гессиан 43.3203 -20.4714 -20.4714 10.1446 Видим, что действительно найден минимум, т. к. компоненты градиента достаточно малы, а гессиан — положительно определенная матрица, в чем можно убедиться с помощью критерия Сильвестра: 43.3203 > 0, det(hes) = 20.3891 > 0. Рассмотрим пример 15.32. [ Пример 15.32. Другой вариант задачи управления роботом £Щз&>шvj а'. -— .' - ^ .-. .". "... I.....'. ;,...J.....;.;„. .vj.....f В примере 15.21 рассматривалась задача об управлении роботом-манипулятором в двумерной постановке. Выяснилось, что решать ее как задачу минимизации невязки, т. е. расстояния между требуемым и фактическим положением рабочего органа манипулятора (схвата), совпадающего с концом последнего стержня, не имеет большого смысла: для любой достижимой точки невязка получается практически равной нулю, а из бесконечного множества возможных решений, т. е. углов поворота стержней (при их числе больше 2) выбор делается, по существу, случайно. Рассмотрим эту задачу в несколько иной постановке. Попадание схвата в нужную точку будем рассматривать как нелинейное ограничение, вырабатываемое функцией hitting (о списке входных параметров см. ниже). Функцию hitting определим так, чтобы кроме самого ограничения она вырабатывала его градиент: function [c,ceq,GC,GCeq)=hitting(q., I,xc,q0) Q=cumsum(q) ; x=[sum(.l.*cos (Q) ) ; sum(l.*sin(Q) } ] ; c=[]; ceq=0.5*sum((x-xc).Л2) ; if nargout > 2 GOU; xql=[-x(2);x(l)]; xq2=[-sum(1(2:3).*sin(Q<2:3)));sum(1(2:3).*cos(Q(2:3)))]; xq3=l(3)*[-sin(Q(3));cos(Q(3))]; GCeq=[s.um( (x-xc) . *xql) ;suni( (x-xc) -*xq2) ;sum( (x-xc) .*xq3) ] ; end
644 Глава 15 Кроме нелинейного ограничения ceq=o зададим также простые ограничения на углы q, каждый из которых не должен выходить из диапазона [~п,п]. Для этого определим ub=pi*ones (1,3), ib=-ub. Целевую функцию построим, исходя из условия наименьших шевелений стержней: взвешенная сумма квадратов разностей начальных углов (вектор qo) и получающихся (вектор q) должна быть минимальной. В качестве весов возьмем сумму длин стержней, которые перемещаются при изменении каждого из углов: для первого угла это сумма всех длин, для второго угла — сумма всех длин, кроме первой и т. д. Эта идея воплощена в функции stir (о списке входных параметров см. ниже). Функцию stir определим так, чтобы кроме значения самой целевой функции она вырабатывала также ее градиент. function [s,g]=stir(q,l,xc,qO) L=cumsum(fliplr(lj); L=fliplr(L); s=0.5*sum(L.*(q-qO)."2) ; if nargout > 1 g=L.*(q-qO); end В каждой из двух функций hitting и stir, задействованных в решении задачи о манипуляторе, содержательно имеется свой список входных параметров, реально используемых в теле соответствующей функции. Однако список дополнительных параметров функции fminco.n должен быть сформирован как единый — этим и объясняется появление лишних входных параметров: qO В hitting И хс В stir. Данные возьмем те же, которые были использованы в примере 15.21: □ начальные углы qO=L0.7 -1 о.5]; О длины стержней 1=[5 5 5]; П требуемое положение схвата хс=[ 12,- 0]. Зададим условия: » options = optimset('Display','final', ... 'GradObj ', 'on', 'GradConsttr', 'on'); После чего обратимся к функции fmincon: » [q, fval]=fmincon(@stir,qO, [] ЛЬ (L П ,lb,ub, . . . Shitting, options:, l,xc,q0) q = 0.944.6 -1.4801 0.-2308
Нелинейные уравнения и оптимизация 645 fval = 1.7826 Напомним, что fval — взвешенная сумма квадратов изменений углов и она не может быть очень малой, коль скоро полученное значение q заметно отличается от начального qo. Чтобы понять, насколько точным получилось попадание схвата в заданную точку, обратимся к функции hitting: » [c,ceq,GC,GCeql = hitting(q,l,xc,qO) Получим значение самой функции ceq=i.i4 8le-ou и ее градиента GCeq=i.0e-004*[0.0946 0.2630 0.1085]. Видим, что попадание схвата в заданную точку (условие ceq=o) выполнилось весьма точно, градиент также достаточно мал. Для сравнения рассмотрим еще одно положение манипулятора, при котором схват находится в заданной точке: стержни (их длины равны 5) представляют собой две боковые стороны и малое основание равнобочной трапеции. Большое основание трапеции — отрезок от неподвижного шарнира до заданной точки (его длина равна 12). Проекция боковой стороны на большое основание равна (12-5)/2=3.5, острый угол при основании трапеции a=acos(3.5/5)=0.7954. Зададим вектор углов q=[a -а -а], а значения всех остальных параметров сохраним прежние. Выполнив команду [c,ceq,GC,GCeq]=hitting(q, l,xc,q.0), получим ceq=o, GCeq=[0 0 0] (абсолютно точное попадание схвата в заданную ТОЧКу). ВЫПОЛНИВ Команду [s,g]=stir(q, l,xc,qO), ПОЛуЧИМ S=4.4727, что в 2,5 раза больше, чем минимальное значение, найденное функцией fmincon. С помощью программы progl5_ll.m проведены указанные вычисления, а их результаты графически отражены на рис. 15.15. function ргод15_11 axesCXlim', [-1 15],'Ylim',[-1 10]); axis equal; grid off; hold on; 1=[5 5 5]; xc=[12; 0]; qlnit=[0.7 -1 0.5]; [XInit,YInit]=hinges(qlnit,1); plot(XInit,YInit,'k:\ 'LineWidth',2); a=acbs(0.7); qTrapz=[a -a -a]; [XTrapz,YTrapz]=hinges(qTrapz,1); plot(XTrapz,YTrapz,'k—','LineWidth',2); options=optimset('Display','final', ... 'GradObj','on', *GradConstr','on *); ub=pi * ones(1,3); lb=-ub; [qOptim,fval]=fraincon(@stir,qlnit, [],[],[],[], lb,ub,Shitting,... options, 1, xc, qlnit);
646 Глава 15 [XOptim,YOptim]^hinges(qOptim,1); plot(XOptim,YOptim,'k-','LineWidth', 2) ; plot([0], [-0.3], 'к'4', 'MarkerSize',15); plot(XInit(l:3},YInit(l:3),'ко'); plot([XInit(4}],[YInit(4}],'ks','MarkerSize',15); plot(XTrapz(1:3),YTrapz(l:3),'ко'); plot([XTrapz(4)],[YTrapz(4>],'ks','MarkerSize', 15); plot(XOptim(1:3),YOptim(1:3),'ко'); plot([XOptiin(4}], [YOptim{4)], ' ks', 'MarkerSize*, 15) ; xlabel('xl'); ylabel('x2'>; hL=legend( 'Начальное-', 'Трапеция', 'Оптимальное') ; set(hL,'FontName','Courier') title ('Три положения манипулятора','FontName",'Courier'); 8 6 4 « 2 0 -2 -4 Три положения манипулятора ■ "" ' ■■"" " * — Начальное — Трапеция Оптимальное • J^^x а /' ^*"""--»»_\. A ^¾ - 0 5 10 XI 1 jPf **ч V* 15 Рис. 15.15. Положения манипулятора 15.5.2. Функции Isqnoniin и fminimax При использовании функций isqnoniin и fminimax, в которых целевая функция является сверткой вектора, также можно задавать ограничения. Для функции isqnoniin доступны только простейшие ограничения типа ib<x<ub. Обращение к; функции isqnoniin в этом случае имеет вид х = isqnoniin(fun,хО,lb,ub,options,P1,P2,... )
Нелинейные уравнения и оптимизация 647 Рассмотрим пример 15.33. I Пример 15.33. Дополнительные параметры функции lsqnoniin {'■' . В примере 15.22 минимум функции отыскивался с помощью функции lsqnoniin. Для этого была определена функция Rosenforock2(x), которая вычисляет компоненты вектора, сумма квадратов которых задает функцию Розенброка. Введем ограничения xi<o, х2>о: lb=[-Inf; 0] ub=[0; Inf] Из стартовой точки х0=[-2;2] функция lsqnoniin находит следующий приближенный результат (точным решением является точка [о; о]): » х = lsqnoniin(@Roseribrock2,хО,ib,ub} х = 1.0е-004* -0.0000 0.7727 Функция lsqnoniin может возвратить довольно много выходных параметров: [х,resnorm,residual,e_flag,inform,lambda,jacofoian] =lsqnonlin(...) Кроме ранее встречавшихся выходных аргументов здесь представлены: П resnorm — значение целевой функции в найденной точке: sum (fun (х) .Л2); О residual — компоненты функции fun(x) в найденной точке; П jacobian — якобиан функции fun в найденной точке. Обращение к функции fminimax мало чем отличается от вызова функции fmincon: x=fminimax(fun,x0,A,b,Aeq,beq,lb,ub,nonlcon,options,PI, P2,...) Рассмотрим пример 15.34. I, Пример 15.34. Поиск минимума функции max Найдем минимум функции max(-xi,xi,-x2,x2> из примера 15.25 вне цилиндра с радиусом 1, т. е. с дополнительным ограничением xj + xij > i. Для обращения к fmincon там был определен вектор-функция piusminus. Определим
648 Глава 15 теперь функцию, задающую ограничение-неравенство (ограничение-равенство, которое здесь не используется, представлено пустым массивом []). function [с, ceq] = circle(х) с = 1-(х(1)Л2+х(2)Л2); ceq = []; Зададим стартовую точку х0= [1; 1] и обратимся к функции fminimax: » х = fminimax(Gplusminus,хО,[],[],[],[],[],[],@circle) Active Constraints: 1 3 4 x = 0.7071 0.7071 Функция fminimax может возвратить довольно много выходных аргументов, значения которых позволяют уточнить информацию о найденном решении: [х,fval,maxfval,exitflag,output,lambda] = fminimax(...) Выполним последнее обращение к функции fminimax в наиболее полной форме: » [х,fval,maxfval,e_flag,inform,lambda] = ... fminimax(@plusminus,xO, [], [], [], [], [], [] ,Gcircle) Active- Constraints: 1 • 3 4 x = .0.7071 0.7071 fval = -0.7071 0.7071 "0.7071 -0.7071 maxfval = 0.7071
Нелинейные уравнения и оптимизация 649 e_flag = 1 inform = iterations: 6 funcCount: 31 stepsize: 1 algorithm: 'minimax SQP, Quasi-Newton, line_search' lambda = lower: [2x1 double] upper: [2x1 double) eqlin: [Oxl double] eqnonlin: [0x1 double] ineqlin: [0x1 double] ineqnonlin: 0.3536 15.6. Управление итерационными процессами Все функции оптимизации и решения нелинейных уравнений, описанные в этой главе, включают в списке своих входных параметров перечень свойств, влияющих на ход итерационных процессов. Эти свойства представлены структурой options, поля которой формируются с помощью функции optimset. Задание значения любого свойства производится парой параметров функции optimset, первый из которых представляет наименование свойства, а второй — его значение: options = optimset('Свойство_1',Значение_1,'Свойство_2',Значение_2,...); х = fxxx(fun,xO,...,options) х = fxxx(fun,x0,..., options,PI,P2,...} Перед входным параметром options может располагаться некоторое количество входных параметров, перечень которых для каждой функции оптимизации индивидуален. Параметры pi, Р2, ..., располагаемые вслед за структурой options, передаются оптимизируемой функции вместе с независимым аргументом х — fun(x,pi,Р2,...). Список большинства параметров, управляющих процессами поиска решений нелинейных уравнений или нахождения минимума функций, приведен в табл. 15.3.
650 Глава 15 Таблица 15.3 Параметр Назначение Значение по умолчанию Diagnostics DiffMaxChange DiffMinChange Display GradC'onstr GradObi Hessian HessMult Jacobian JacobMult LargeScale- LievenbergMarquardt MaxFunEvals Вывод диагностической информации off о функции fun (од | off) Максимальный шаг no переменной для le-1 вычисления конечных разностей Минимальный шаг по переменной для 1е-8 вычисления конечных разностей Режим отображения информации о шагах итерационного процесса: • off — вывод отключен; • iter — вывод на каждой итерации; • notify — вывод в случае необходимости; • final—финальный вывод Определен ли пользователем градиент off для нелинейных ограничений (on | off) Определен ли пользователем градиент off для обрабатываемой функции (on I off) Определен ли пользователем гессиан off для обрабатываемой функции (on | off) Определена ли пользователем функция 11 умножения на гессиан (указатель I [ ]) Определен ли пользователем якобиан off для обрабатываемой функции (on | off) Определена ли пользователем функция П умножения на якобиан (указатель | [ ]) Использовать ли алгоритм on large-scale, если это возможно (on | off) Заменить ли алгоритм Гаусса—Ньютона на алгоритм Левенберга—Марквардта (on | off) Максимальное количество обращений к функции fun Maxlter Максимальное количество итераций
Нелинейные уравнения и оптимизация 651 Таблица 15.3 (окончание) Параметр Назначение Значение по умолчанию MaxPCGlter Максимальное количество итераций в методе сопряженных градиентов (pcg) MinAbsMax Количество компонентов вектора- О функции для минимизации абсолютных значений TolCon Прекращение итераций при нарушении ограничений То!Fun Прекращение итераций при достижении точности по значению-функции TdlPCG Прекращение итераций для алгоритма PCG 0.1 То1Х: Прекращение итераций при достижении 1е-б минимального шага по X
Глава 16 Математическое программирование Решение задачи безусловной или условной минимизации, вообще говоря, зависит от стартовой точки. Получить все минимумы (равно как и все решения нелинейного уравнения или системы уравнений) можно либо путем теоретического анализа (асимптотическое поведение функции и т. п.), либо (не всегда с полной уверенностью) путем использования большого количества стартовых точек. Один из авторов был свидетелем того, как его коллега искал минимум функции 6 переменных, заданной алгоритмом ее вычисления. Задача решалась не в среде MATLAB (его тогда не было), но с помощью примерно тех же самых алгоритмов. Многочисленные стартовые точки давали решения со значением целевом функции порядка Ю-3. Между тем из общих соображений было достоверно известно, что истинный минимум целевой функции имеет порядок 10~6, т. е. примерно в 1000 раз меньше! Однако есть класс задач условной минимизации, называемых задачами математического программирования, в которых точка минимума либо единственна, либо множество этих точек легко обозримо. Под задачами математического программирования обычно понимают задачи поиска минимума линейной или квадратичной функции в многогранном множестве. Эти задачи называются соответственно задачами линейного и квадратичного программирования. 16.1. Линейное программирование Для решения задачи линейного программирования в MATLAB используется функция linprog. Область поиска для нее задается следующими условиями: П а*х<=ь — линейные неравенства (а — матрица, ь — вектор); П Aeq*x=beq — линейные уравнения (&eq — матрица, beq — вектор); □ ib<=x<=ub — ограничения на координаты (lb, ub — два вектора). Целевая функция f ■ *х в linprog задается вектором коэффициентов f.
654 Глава 16 Формы обращения к этой функции: х = linprog (f, A,.b,Aeq,bsq) х = linprog (f. A,b,Aeq, beq, lb, ub) x = linprogff,A,b,Aeq,beq,lb,ub,xO} x = linprog(f,A,b,Aeq,beq,lb,ub,xO,options) [x,fval] = linprog(...) [x,fval,exitflag] = linprog(...) [x,fval,exitflag,output] = linprog(...) [x,fval,exitflag,output,lambda] = linprog(...) Семантика входных и выходных параметров очевидна. Единственное необходимое пояснение касается стартовом точки хо. В большинстве случаев она не нужна (а если все же задана, то игнорируется). В функции linprog по умолчанию используется так называемый прямо- двойственный алгоритм, при использовании которого одновременно решается как данная задача, так и двойственная к ней (см. ниже). Впрочем, решение двойственной задачи не выдается. Если для свойства Largescale установлено значение off, будет использоваться хорошо известный симплекс- метод линейного программирования, для которого нужна стартовая точка хО. Однако если стартовая точка не задана, она выбирается автоматически. Рассмотрим примеры 16.1 и 16.2. I Пример 16.1. Задача максимизации дохода ? ' ] Рассмотрим условное производство столов и стульев. Сведения о затратах ресурсов на единицу продукции, их наличии и о доходе от производимой продукции отражены в табл. 16.1. Таблица 16.1 Наименование ресурса Древесина (кг/ шт.) Кожа (м2/ шт.) Клей (г/ шт.) Труд, затраты (чел-час/ шт.) Доход (руб./ шт.) Продукция Стул 5 0.5 100 10 10 Стол 25 - 250 10 20 Ограничения по ресурсу 500 15 7500 400
Математическое программирование 655 Задача производственного планирования заключается в том, чтобы составить план выпуска стульев и столов, обеспеченный имеющимися ресурсами и дающий максимально возможный доход. Ее математической моделью является-задача линейного программирования (ЗЛП) в стандартной форме — найти х.1 и Х2 такие, что функция f (х)=10x1+20x3 достигает максимума при следующих ограничениях: 5хг + 25X2 S 500 0.5xi < 15 lOOxi + 250х2 < 7500 10xi + Юх2 < 400 xi > 0, х2 > 0 Для обращения к функции linprog подготовим входную информацию: П вектор коэффициентов целевой функции f=flO; 20]; П матрицу коэффициентов системы линейных неравенств а=[5 25; 0.5 0;:100 250;10 10J; О вектор свободных членов системы линейных неравенств ь=[50.0; 15; 7500; 400]; П вектор нижних границ для переменных ib=zeros (2,1). Функция linprog ищет минимум, а в постановке задачи идет речь о максимуме, поэтому необходимо либо сменить знак коэффициентов целевой функции f, либо поставить знак минус перед именем этого вектора: [x,fval] = linprog{-f,А,Ь, [], [],ib) Получим следующие результаты: х = [25 15] fval = -550" Таким образом, найден оптимальный план мебельного производства: надо выпустить 25 стульев и 15 столов, при этом получится доход 550 руб. План получился целочисленным, однако в общем случае решение может оказаться и вещественным. Если целочисленность решения — обязательное требование, его пало включать в постановку задачи, однако в MATLAB пет специальных функций для решения общей задачи целочисленного линейного программирования. Для любой ЗЛП можно сформулировать так называемую двойственную задачу. Пусть в исходной задаче требуется найти максимум f'*x при а*х<ь и о<х. Тогда в двойственной задаче требуется найти минимум Ь' *у при a' *y>f И 0<у.
656 Глава 16 Сформулируем задачу, двойственную к рассмотренной в примере 16.1. Чтобы привести неравенство к требуемому виду, умножим его на -1, получим -A'*y<-f. Необходимо также скорректировать вектор нижних границ: lb = zeros(4,1) Обращение к функции linprog теперь имеет такой вид: [y,gval] = linprog (b,-A',-f, [], [], lb) Получим следующие результаты: у =[0.50 0.00 0.00 0.75] gval = 550.0000 Видим, что значения целевых функций совпадают (если учесть искусственно внесенный минус в целевой функции прямой задачи). Это совпадение не случайно, о нем говорит теорема двойственности в ЛП. Значения двойственных переменных имеют экономическую интерпретацию: они представляют собой оценки ресурсов. Так, нулевые значения переменных у2 и у3, соответствующих ресурсам кожа и клей, говорят, что эти ресурсы не являются ценными, поскольку для производства 25 стульев и 15 столов имеющиеся количества этих ресурсов избыточны, в чем можно убедиться, подставив значения xi=25, хг=15 в левые части неравенств прямой задачи. Значение yi=0.5 говорит о том, что при увеличении ресурса древесина на некоторое небольшое количество Д; можно получить дополнительный доход о.5-Дь Аналогично значение у„=о.75 говорит о том, что при увеличении ресурса труд, затраты на некоторое небольшое количество Д4 можно получить дополнительный доход 0.75-Д4. Положим, например, Ai=o, Д«=40 т. е. возьмем ь= [500; 15; 7500; 440]. Решив заново прямую ЗЛП, получим х *= [30 14] fval = -580 Видим, что (с учетом измененного знака fval) доход действительно увеличился на 0.75-Д4=30. Решение задачи ЛП, т. е. точка оптимума, может быть не единственным (хотя оптимальное значение целевой функции определяется однозначно). ! Пример 16.2. Задача линейного программирования " ц~ '' ~ г "I Рассмотрим задачу: найти максимум функции г=хг+х2 при o<xt<2 (i=i,2) и xi+xj<3. Эти неравенства задают на плоскости квадрат размером 2X2 со срезанной вершиной в правом верхнем углу (рис. 16.1).
Математическое программирование 657 Подготовим данные: » lb = zeros(2,1); » ub = 2*ones(2,l); » A = ones(1,2) ; » b = 3; » f = A; и обратимся к функции linprog: » [x,fval] = linprog(-f,A,b,[],[],lb,ub) x = 1.5000 1.5000 fval = -3.0000 Целевая функция принимает одно и то же значение (f=3) во всех точках отрезка с концами [1 2], [2 1]. Для концов отрезка это легко проверить подстановкой их координат в выражение целевой функции. Точка х=[1.5 1.5] является серединой этого отрезка. Для двух переменных ЗЛП имеет простую геометрическую интерпретацию. Ограничения на переменные определяют выпуклый замкнутый многоугольник — область допустимых значений переменных. Функции цели соответствует прямая линия (в нашем примере x+y=const). Если параллельно перемещать линию функции цели, то она сначала коснется одной вершины (или грани) допустимой области значений, а потом — противоположной вершины (или грани). Одно из этих положений соответствует минимуму целевой функции, а другое — максимуму. Это объяснение наглядно демонстрирует рис. 16.1, на котором маркером выделена точка, найденная с помощью функции linprog. Для построения этого рисунка использовалась программа iinprog_draw с последующей ручной корректировкой полученного изображения (штриховка и маркировка функции цели). function linprog_draw axes('Xlim',[-0.5 2.5],'Ylim',[-0.5 2.5]}; axis equal; hold on; x=[0 2 2 1 0 0]; y=[0 0 1 2 2 0]; plot(x,y,'k'); line(2,1, 'Marker', '.','MarkerSize',20}; lined,2, 'Marker', '. ', 'MarkerSize',20} ; lined. 5,1.5, 'Marker', '. ', 'MarkerSize', 20); xlabeK'xl'}; ylabel ('x2 ') ;
658 Глава 16 line([-0.5,0.5],[0.5,-0.5]) line([-0.5,1.5],[1.5,-0.5]) line([-0.5,2.5], [2.5,-0.5]) line([0.5,2.5],[2.5,0.5]) Рис. 16.1. Геометрическая интерпретация ЗЛП 16.2. Бинарное линейное программирование Задача бинарного линейного программирования отличается от обшей задачи более жесткими ограничениями на переменные, которые могут принимать только два булевых значения: 0 или 1. Решение задачи в этом случае использует стандартный алгоритм линейного программирования в сочетании с методом ветвей и границ. Чтобы найти оптимальное решение в булевых переменных, строится серия "ослабленных" задач линейного программирования, в которых на переменные (сначала на все) накладываются более слабые ограничения: 0<x(i><l. Алгоритм создает дерево поиска многократным добавлением булевых ограничений. На каждом шаге ветвления алгоритм выбирает некоторую переменную x(i), текушее значение которой не целое, добавляет ограничение x(i)=o, чтобы сформировать одну ветку, и ограничение x(i)=i, чтобы сформировать альтернативную ветку. Этот процесс можно представить двоичным деревом, в котором каждый узел соответствует введению булева ограничения по одной нз переменных.
Математическое программирование 659 В каждом узле двоичного дерева алгоритм решает "ослабленную" задачу линейного программирования и выясняет, надо ли строить две ветви от этого узла или переходить к другому узлу. При этом имеется три возможности: П "ослабленная" задача в текущем узле не имеет решений или значение целевой функции хуже (больше), чем найденное ранее наилучшее булево решение; этот узел удаляется из дерева, и алгоритм переходит к другому узлу в соответствии с некоторой стратегией выбора; О алгоритм обнаруживает новое допустимое булево решение со значением целевой функции лучшим (меньшем), чем найденное ранее наилучшее булево решение; алгоритм корректирует текущее наилучшее решение и переходит на следующий узел; П "ослабленная" задача в текущем узле дает значение целевой функции лучше (меньше), чем найденное ранее наилучшее булево решение, однако это решение не удовлетворяет булевым ограничениям. В этом случае происходит расширение поиска. Для решения задачи бинарного линейного программирования в MATLAB 7 используется функция bintprog. Формы обращения к этой функции: х = bintprog(f} х = bintprog (f, A, b} x = bintprog(f,A,b,Aeq,beq) к = bintprog(f ,A,b, Aeq,beq,:xO) x = bintprog(f,A,b,Aeq,beq,xO,options) [x, fval] = bintprog (...) [x,fval,exitflag] = bintprog(...) [x,fval,exitflag,output] = bintprog(...) Семантика входных и выходных параметров та же, что у функции linprog. Через входную переменную options с помощью функции optimset задаются параметры, управляющие ходом вычислительного процесса и его отображением на мониторе. Отметим некоторые из них, характерные именно для функции bintprog: П 'Maxiter' — максимально допустимое число итераций, значение по умолчанию равно l00000*nuniberOfVariables (nuiriberOfVariables — количество переменных); П 'MaxRLPiter' — максимально допустимое число "ослабленных" задач линейного программирования, значение по умолчанию равно 10 0 * numberOfVariables; □ 'MaxNodes' — максимально допустимое число узлов дерева, значение по умолчанию равно 1000*numberOfVariables;
660 Глава 16 П 'MaxTime' — максимальное время решения (в секундах), значение по умолчанию 72оо; П ■ Toixinteger' — предельно допустимое отличие переменных от целых, значение по умолчанию 1. е-8. Два параметра определяют стратегию выбора узла и выбора переменной, по которой производится ветвление: П 'Nodesearchstrategy' — возможны два варианта: 'df' — используется стратегия поиска'в глубину, 'Ьп' — используется стратегия поиска, которая выбирает узел с самым низким (т. е. наилучшим) значением целевой функции. По умолчанию используется 'Ьп*; □ 'Branchstrategy' — возможны два варианта: 'mininfeas' — выбирается переменная со значением, минимально отличающимся от целого; т. е. переменная, величина которой наиболее близка к 0 или 1 (но не 0 или I), 'maxinfeas' — выбирается переменная со значением, максимально отличающимся от целого, т. е. переменная, величина которой наиболее близка к 0.5. По умолчанию используется 'maxinfeas'. Возможные значения выходного параметра exitflag: П 1 — успешное завершение вычислений, найлено решение х (и, если было указано в обращении, значение целевой функции fval); По— число итераций превысило заданное в optimset значение параметра Maxlterj П -2 — задача сформулирована некорректно; П -4 — число узлов дерева превысило заданное в optimset значение параметра MaxNodes; П -5 — время поиска превысило заданное в optimset значение параметра MaxTime; П -б — число решаемых "ослабленных" задач линейного .программирования превысило заданное в optimset значение параметра MaxRLP. Перейдем к рассмотрению примера 16.3. ! Пример 16.3. Задача 6 разбиении множества'""- '■ > ■?,* В математическом фольклоре эта задача носит образное название "задачи о камнях". Суть се такова: имеем кучу камней разного веса (какие-то веса могут и совпадать). Требуется сформировать из этих камней две новые кучи так, чтобы веса этих куч отличались друг от друга как можно меньше. Несмотря на простоту формулировки, "задача о камнях" относится к категории так называемых NP-полных задач [52].
Математическое программирование 661 Чтобы сформулировать "задачу о камнях" в терминах бинарного программирования, введем вектор весов камней w. Тогда вес всей кучи будет равен sum(w). Компоненты вектора решения х будем интерпретировать так: если x(i)=i — положим i-й камень в первую кучу из двух, если x(i)=o — положим i-й камень во вторую кучу. Потребуем, чтобы вес первой кучи был максимальным, но не превосходил половины общего веса всех камней. Это можно записать так: найти max(Zw(i)*x{i}) при Ew(i)*-x(i}<o.5*sum(w}. Для обращения к функции bintprog подготовим вектор весов w =[19538]. Эти веса будут играть троякую роль: О они являются коэффициентами целевой функции (поскольку ищется ее максимум, в обращении берется вектор -w); □ они же являются элементами однострочной матрицы ограничений; П половина их суммы является правой частью ограничения. Обратимся к функции в форме, обеспечивающей выдачу максимального количества итоговой информации: [х,fval,exitflag,output] = bintprog(-w,w,0.5*'sum(w)) Получим результат: Optimization terminated. x = 1 1 0 1 0 fval = -13 exitflag = 1 output = iterations: 6 nodes: 3 time: 0.05007200000000 algorithm: 'LP-based branch-and-bound' branchStrategy: 'maximum integer infeasibility' nodesrchstrategy: 'best node search' message: 'Optimization terminated.'
662 Глава 16 Интерпретация результатов: в первую кучу пало положить три камня с номерами I, 2 и 4; во вторую кучу надо положить камни 3 и 5. При этом веса обеих куч будут равны 13. 16.3. Решение матричных игр Линейное программироваггие можно использовать для решения матричных игр, т. е. для поиска оптимальных смешанных стратегий участников игры. Матричная игра задается платежной матрицей А=(а1;,), строки этой матрицы соответствуют чистым стратегиям первого участника игры р, столбцы — чистым стратегиям второго участника q. Если р выберет стратегию i, a q — стратегию j, то р получит (a q заплатит) сумму, равную ап. Смешанная стратегия участника р представляет собой вектор относительных частот Р={р,), с которыми участник использует отдельные чистые стратегии при повторных актах игры. Аналогично определяется смешанная стратегия участника q — это вектор относительных частот q=(qj). Математическое ожидание выигрыша р (проигрыша q) при выборе ими смешанных стратегий р и q выражается формулой p'*A*q (предполагается, что р и q— векторы- столбцы). Ясно, что любая чистая стратегия является частным случаем смешанной (когда одна из относительных частот равна 1, а остальные — о). Основной результат теории матричных игр — теорема Джона фон Неймана, — утверждает, что max min(p' * А * q) = min max (p' * A * q). p q q p Эта величина обозначается v и называется ценой игры, а те р и q, при которых она достигается, называются оптимальными смешанными стратегиями участников игры. Игру естественно назвать справедливой, если ее цена равна о. Смысл оптимальности стратегий р и q таков: если р будет придерживаться оптимальной стратегии р, ему гарантируется выигрыш не менее v, какой бы (чистой или смешанной) стратегии ни придерживался q. Если q будет придерживаться оптимальной стратегии q, ему гарантируется проигрыш не более v, какой бы (чистой или смешанной стратегии) ни придерживался р. Гарантия подразумевает, что каждый участник делает свой ход (выбор стратегии), не зная хода соперника. Для игр с "узкой" матрицей (гхп или тх2) существуют простые графоаналитические приемы решения, т. е. нахождения цены и оптимальных смешанных стратегий, однако в общем случае это довольно сложная задача.
Математическое программирование 663 Чтобы найти иену игры с платежной матрицей A=(aiS) размером mXn и оптимальные стратегии участников, надо решить пару двойственных задач линейного программирования: 1. Найти вектор х=[хг,-.. .,хга], для которого F=xi+...+xra достигает минимума при условиях А'*х>1п (здесь in — вектор-столбец из п единиц). 2. Найти вектор y=[yi;.. .,уГ1], для которого G=yi+...+yn достигает максимума при условиях А*у<1„, (здесь im — вектор-столбец из m единиц). Из теорем двойственности в ЛП следует, что F„lln=Gma)t. Тогда цена игры v=i/Frnin=i/G],,av, а оптимальные смешанные стратегии p=v*x, q=v*y. Случай v=o обсуждается в примерах 16.4 и 16.5. I Пример ^:6.4г:Ма^р!|адная"карточная игра i Рассмотрим игру "Жулик" (название станет ясно из дальнейшего описания). Ее правила таковы: каждому участнику сдается три карты — красный туз, черный туз и двойка, причем у р двойка красная, а у q — черная. Этот расклад известен обоим участникам. Каждый выбирает из своих трех карт одну и кладет ее рубашкой вверх на стол. Затем карты открывают и определяют исход игры. Если обе карты одного цвета, выигрывает р, если разных — Q. Сумма выигрыша/проигрыша определяется достоинством карты, выложенной победителем: если это туз — одно очко, если двойка — два очка. Если открылись две двойки, объявляется ничья (платеж равен нулю). Платежная матрица этой игры представлена в табл. 16.2. Таблица 16.2 Красный туз Черный туз Красная двойка Красный туз 1 -1 2 Черный туз -1 1 -1 Черная двойка -2 1 0 Чтобы решить игру с помощью функции linprog, подготовим данные для прямой и двойственной задач: » А = [1 -I -2;-1 I 1,-2 -1 0J; >> % Обращение для прямой задачи: » [x,fval] = linprog{ones(3,1),-A',-ones (3,1},[],[],zeros(3,1)) Optimization terminated successfully. x = 0.0.000 3.0000 2.0000 22 2-ях 8'W
664 Глава 16 fval = 5.0000 » % Обращение для обратной задачи: » [y,gval] = linproq (-ones (3,1) ,A,ones (3,.1), Г], [], zeros (3,1)) Optimization terminated successfully. У = 2.0000 3.0000 0.0000 gval = -5.0O0O Отрицательное значение gval вызвано изменением знака перед вектором коэффициентов целевой функции. Цена игры: v=i/fvai=i/5. Смешанные стратегии: p=v*-x=[0 3/5 2/5], q=v*y=[2/5 3/5 0]. Обсудим вопрос о справедливости этой игры. На первый взгляд, особенно если ограничиться словесной формулировкой правил, игра кажется справедливой. Легко себе представить, как участник р ("Жулик") уговаривает сыграть другого участника q (которого в данной ситуации можно назвать "Лохом"). Лоху кажется, что все в порядке, и он садится играть. Однако после, скажем, 100 игр выяснится, что Лох оказался в проигрыше (не менее 20 очков). И дело не в везении или невезении — просто Жулик придерживался оптимальной для себя стратегии: он никогда не выкладывал на стол красного туза, в 60% игр выкладывал черного туза, а в 40% игр красную двойку, чередуя их случайным образом. И что бы ни делал Лох, если он не сумеет подглядеть, какую карту выложил Жулик, в длинной серии игр он окажется в проигрыше (хотя в отдельных играх будет выигрывать, что лишь усыпит его бдительность). Его проигрыш будет в среднем 20 очков на 100 игр, если он будет придерживаться оптимальной для себя стратегии: никогда не выкладывать на стол двойку, в 60% игр выкладывать черного туза, а в 40% игр красного туза, чередуя их случайным образом. ( Замечание ) Как раз для справедливых игр с ценой v=0 способ решения игры с помощью ЛП не срабатывает. | Пример 16.5. Матричная игра "Орёлгрёшка"" ' - у;уь£'--' *%М Сюжет игры "Орел-решка" можно описать так: участники кладут на стол по монете равного достоинства, прикрывая ее ладонью. Затем они одновремен-
Математическое программирование 665 но убирают руки. Если монеты лежат кверху одной и той же стороной, обе монеты забирает р, в противном случае обе монеты забирает q. Первая чистая стратегия каждого участника: положить на стол монету кверху "орлом", вторая стратегия — кверху "решкой". Платежная матрица этой игры or=[1 -i; -l l]. Интуитивно очевидно, что цена этой игры v=o, оптимальные смешанные стратегии р= [1/2 1/2], q= [1/2 1/2]. Составим две задачи ЛП для этой игры: F=xl+x2 -> rain G=yl+.y2 -» max xl-x2>l yl-y2<l -xl+x2>l -yl+y2<l xl,x2>0 yl,y2>0 Видим, что офаничения первой задачи несовместны: сложив первые два неравенства, получим о>2. Эта задача ЛП не имеет допустимых планов. Для второй задачи, если положить yi=yj=t, то при любом t>o точка у удовлетворяет всем неравенствам, а значение целевой функции G=2*t может стать сколь угодно большим. Видим, что целевая функция этой задачи не ограничена сверху на множестве допустимых планов. Испытаем MATLAB на этих задачах. Для первой задачи получим: х = [7.2795 8.2795], fval = 15.5591 Найденный вектор, однако, не удовлетворяет неравенствам задачи: OR'*x = [-1.0000 1.0000] Впрочем, MATLAB выдает предупреждение: Exiting: One or more of the residuals, duality gap, or total relative error has stalled: the primal appears to be infeasible (and the dual unbounded). (The dual residual < TolFun=1.00e-008.) Для второй задачи получим более осмысленный результат, не противоречащий нашему предварительному анализу (значения переменных и целевой функции весьма велики): у = 1.0еЮ10* [1.2747 1.2747] gval = --2.5495е+010 Найденный вектор удовлетворяет неравенствам задачи: CR*y = [0 0] MATLAB выдает такое же предупреждение.
666 Глава 16 С задачами этого рода (v=o) можно справиться очень простым приемом: надо прибавить ко всем элементам матрицы платежей некоторую константу с. Цена такой модифицированной игры v=c, оптимальные стратегии участников исходной и модифицированной игр одинаковы (пример 16.6). | Пример 16.6. Модифицированная матричная игра - ^.1^ ;р. ■] Рассмотрим этот прием на примере игры "Разоблаченный жулик". Лох, игравший с Жуликом, разобрался, что к чему, и предложил отменить исключительное правило, касающееся двух двоек — именно оно давало Жулику преимущество. В соответствии с общим правилом, поскольку цвета двоек различны, 2 очка в этой ситуации выигрывает бывший Лох. Платежная матрица теперь станет такой: a=[1 -l -2,--1 1 1,-2 -1 -2], пена игры v=o, так что непосредственно получить удовлетворительные результаты с помощью MATLAB не удастся. Поэтому предварительно добавим ко всем элементам матрицы а по 1 и обратимся к функции linprog: » [x,fval] = linprog(ones(3,1),-(A+l)',-ones(3,l),[],[],zeros(3,l}) Optimization terminated successfully, k = 0.0000 0.6667 0.3333: fval = 1.0000 Цена модифицированной игры (a+i) равна l, а исходной — о, оптимальная смешанная стратегия разоблаченного Жулика р=[0 2/3 1/3]. А теперь решим двойственную задачу: » [y,gval] = linprog(-ones(3,1},A+l,ones(3,1},[],[].zeros(3,1)) Optimization terminated successfully. У = 0.5000 0.0000 0.5000 g.val = -1.0000 Оптимальная смешанная стратегия поумневшего Лоха q=[l/2 о 1/2].
Математическое программирование 667 16.4. Квадратичное программирование Для решения задачи квадратичного программирования предназначена функция quadprog. Область поиска для нее задается так же, как при решении задачи линейного программирования (см. разд. 16.1). Целевая функция задачи квадратичного программирования имеет вид 0.5*x'*H*x+f • *х и в обращении к quadprog представлена двумя параметрами — симметричной матрицей н и вектором f. х = quadprog(Н,f,А,Ь) х = quadprog(H,f,А,b,Aeq,beq) х = quadprog(H,f,A,b,Aeq,beq,lb,ub) x = quadprog(H,f,A,b,Aeq,baq,lb,ub,xO) x = quadprog (H, f, A, b,Aeq,beq, lb, ub,xO, options) x = quadprog(H,f,A,b,Aeq,beq,lb,ub,xO,options,pi,p2,...) |x,fval] = quadprog(...) [x,fval,exitflag] = quadprog(...) [x,fval,exitflag,outpjt] = quadprog(...) [x,fval,exitflag,output,lambda] = quadprog(...) Если в обращении к функции quadprog заданы только верхние и нижние границы или только линейные уравнения, то используется метод Ньютона с доверительным интервалом и метод сопряженных градиентов. В противном случае применяется метод активного набора, для которого нужна стартовая точка хО. Однако если стартовая точка не задана, она выбирается автоматически. То же самое происходит, если в параметрах options было установлено 'LargeScale'='off'. Рассмотрим пример 16.7. I Пример 16.7. Задача квадратичного программирования Найдем минимум положительно определенной квадратичной функции х2! 4 Xj в треугольнике, ограниченном прямыми xi=2, х2=1, xi+2x2=2. С учетом коэффициента 0.5 в определении квадратичной целевой функции (см. выше) введем матрицу н=2*еуе(2) и вектор f=zeros(2,i>. Неравенства хт<2 и х2<1 отнесем к ограничениям на координаты, положив ub=[2;i], а неравенство xi+2x,.>2 представим в виде а*х<ь с матрицей а=[-1 -2] и вектором Ь=[-2]. Обратимся К фунКЦИИ quadprog: »Н=2*еуе(2); f=zeros(2,1); ub=[2;l]; » A=[-l -2]; Ь=[-2]; :» [x,fval] = quadprog(H,f,A,b,[J,[J,[],ub)
668 Глава 16 Warning: Large-scale method does not currently solve this problem formulation, switching to. medium-scale method. Optimization terminated successfully, x = 0.4000 0.8000 fval = 0.8000 Причина предупреждения заключается в том, что были заданы верхние границы, а также линейное неравенство, поэтому произошло переключение на метод активного набора, для которого была нужна стартовая точка х0. Хотя стартовая точка и не была задана, функция успешно выполнила работу. Геометрическая интерпретация полученного, результата достаточно очевидна. Допустимая область изменения переменных xi, х2 задана прямоугольным треугольником (рис. 16.2), а минимизируемая функция цели представлена концентрическими окружностями с центром в начале координат. Постепенно увеличивая радиус этих окружностей, мы находим первую точку встречи с ребром допустимой области, в которой функция цели достигает минимума. При последующем увеличении радиуса функция цели достигает самой удаленной вершины треугольника, где достигается максимум. Рисунок 16.2 получен с помощью функции qp_tst.m, текст которой приводится ниже. function qp_tst sq5=sqrt(5) ; hold, on; axis equal t.= -0.1:0.05:pi/2+0.1; cost^cos(t); sint=sin(t); r - [l/sq5 2/sq5 1 3/sq5 2 sq5]; for i=length(r):-1:1 rc=r(i)*cost; rs=r(i)*sint; plot(re, rs); end plot([0 2 2 0), [1 0 1 l],'k-'); text(0.3,-0.1,'0.2'}; text(0.75,-0.1, '0.8'}; text(l.0,-0.1,'1.0'); text(l.35,-0.1, 4.8'); text(2.05,-0.1, '4'); text(2.3,-0.1,'5') ; line -(0.4,0.8, 'Marker', ' . ', 'MarkerSize', 20) ;
Математическое программирование 669 text(0.3,0.7,'min'); line (2,1, 'Marker', '. ', 'MarkerSize', 20} ,- text(2.05,l.l,'max'}; xlabel('xl'}; ylabel('x2'); title('Линии уровня функции х1л2+х2л2, ее min и max в треугольнике', 'FontName','Courier'); ,, 2 4L ^ as Динии уровня функции х1 +х22, ее min и щах .в треугольнике -0.5 Рис. 16.2. Геометрическая интерпретация задачи квадратичного программирования Теперь найдем максимум той же функции. Для этого в обращении к quadprog перед именем матрицы н и вектора f поставим знак минус: » [x,fval] = quadprog(-H,-f,A,b,[],[],[],ub} Warning: Optimization terminated successfully, x = 2 1 fval = -5 Рассмотрим пример 16.8.
670 Глава 16 Пример 16.8. Задача о ритмичных поставках ■ • ->-? ^¾¾¾^ . ^"-.v v^lK; На склад от поставщиков поступает некоторый однородный продукт (например, горючее). Со склада этот продукт передается на, производство (например, тепла и/или электроэнергии). От поставщиков продукт может поступать не очень ритмично, но на производство он должен передаваться как можно более равномерно. Рассмотрим эту задачу в дискретной постановке, т. е. будем считать, что все акты приема-передачи продукта происходят по тактам в моменты t=l, 2, ... Введем величины, характеризующие функционирование склада (табл. 16.3). Таблица 16.3 № п/п Параметр Обозначение 1 Число тактов п 2 Вектор поставок продукта р= [ р,, р2,. -, р„ ] 3 Емкость склада maxV 4 Минимальное нормативное количество продукта minV на складе 5 Начальная загрузка склада v0 OfininVSVofinaxV 6 Вектор передачи продукта на производство х= [ xi, хг, - ■ ■, хп] Первые пять параметров — входные (их значения должны задаваться), вектор х — выходной параметр (должен вычисляться при решении задачи). Будем считать, что суммарное количество продукта, поступившего на склад, должно быть примерно равно суммарному количеству продукта, переданного со склада: 1=1 i=l Максимально равномерная передача продукта на производство (с учетом оговоренного примерного равенства) достигается, если целевая функция V (x.i - мр)2 —> min (здесь мр — среднее по всем компонентам вектора р, i=i которое может быть найдено с помощью функции mean(p)). Целевую функцию преобразуем, раскрыв скобки и приведя подобные члены: xl + xl + . . . + х2 - 2 ■ Мр • (хх. + х, + . . . + х„} + п ■ (Мр)? .
Математическое программирование 671 В матричном виде квадратичную часть этого выражения запишем так: о.5*х'*н*х, где матрица н=2*еуе (п); линейная часть равна f *х, где вектор f=-2*Mp*ones(n, 1). Свободный член n- (Mp)z не может быть включехг в обращение к функции quadprog, его придется учитывать отдельно. Офаничения задачи заключаются в том, что в любой момент t количество продукта на складе vt удовлетворяет неравенствам rainv<vt^uaxv. Это количество выражается простой формулой Vt = Ч + £ Pi " X *i- Подставим это выражение в двойное неравенство и разрешим его относи- телыю \ х±, получим ограничения задачи: t t t + ]jT Pl - maxV < £ Xi < V0 + >T Pi - Vt = l,n minV . Вектор s, содержащий суммы ^ pi5 можно получить, выполнив команду i = l s=cumsum(p). Поступить таким же образом с вектором х невозможно, поскольку заранее он неизвестен. Вместо этого введем новые переменные: ус = У^х1- В матричной форме это соотношение можно записать так: у=ь*х, где матрица l = 10 0 110 111 111 111 1 о 1 1 Ее можно создать, выполнив команду L=tril (ones (n)). Старые переменные выражаются через новые с помощью обратной матрицы: х=ъ_1*у. Через новые переменные квадратичная часть целевой функции выражается так: 0.5*y'*Hnew*y, где Hnew = inv(L)'*H*inv(L). Линейная часть целевой функции равна fnew'*x, где вектор fnew=inv(L.) ■ *f.
672 Глава 16 Ограничения для новых переменных можно представить в форме ib<y<ub, где векторы lb, ub задаются формулами: lb = (V0-maxV)+s ub = (V0-minV)+s (скаляры vo-maxv и vo-minv прибавляются к каждому элементу вектора s). Зададим конкретные данные: » п=5; р=[10,25,5,10,30]; maxV=40; minV=0; V0=5; С помощью приведенных выше формул подготовим данные для обращения К функции quadprog: » Mp=mean(p) Мр = 16 » s=cumsum(p) ; » lb=(V0-maxV}+s; » ub=(V0-minV)+s; » L=tril(ones(n)}; » invL=inv(L); » TinvL=invL'; » H=2*eye(n); » Hnew=TinvL*H*invL; » f=-2*Mp*ones(n,1); » fritew=TinvL*f; Найдем решение задачи для новых переменных у: » [у, fval] = quadprog (Hnew, fnew, [],[],[],[] ,1b, ub} Optimization terminated successfully: Relative function value changing by less than OPTIONS.TolFun У = 13.7500 27.5000 41.2500 55.0000 71.0000 fval = -1.2598e+003 Аномально большое (к тому же отрицательное) значение целевой функции fval объясняется очень просто. Когда формировалось выражение целевой функции, были учтены квадратичная и линейная части, а для свободного
Математическое программирование 673 члена п*(Мр)г в обращении к функции quadprog не нашлось места. На самом деле это слагаемое £0=п*мрЛ2=12во надо добавить к fval — получится скромное значение 20.25. Вернемся к вектору старых переменных х: » x=invL*y X = 13.7500 13.7500 13.7500 13.7500 16.0000 » Mx=enean(x) Мх = 14.2000 Теперь можно восстановить значение целевой функции, равное » sum((x-Mp).Л2} ans = 20.2500 Дополнительно найдем остаток продукта на складе после каждого такта: » V=V0+cumsum(p)-cumsum(x) ' V = 1.2500 12.5000 3.7500 0.0000 14.000.0 По этому результату видно, что емкость склада (maxv=40) ни разу не была превышена, но на четвертом такте склад полностью опустошался.
Глава 17 Метод Монте-Карло В математике существует целое направление, связанное с методом Монте- Карло. Оно занимается использованием случайных чисел для решения различных математических задач: интерполяции, вычисления интегралов, решения дифференциальных и интегральных уравнений, решения систем линейных уравнений, поиска экстремума, моделирования процессов и т. д. Преимущества недетерминированных методов особенно ярко проявляются при решении задач большой размерности, когда применение традиционных детерминированных методов затруднительно или совсем невозможно. Границы между простым и трудным, возможным и невозможным с развитием вычислительной техники сдвигаются вдаль, но существуют всегда. Основной недостаток недетерминированных методов — их медленная сходимость, что вынуждает искать компромисс между невысокой точностью результатов и большим расходом машинного времени. Вначале для получения случайных чисел использовались заранее составленные таблицы и физические датчики. Очевидным недостатком таблиц является их ограниченный объем, а использование физических датчиков наталкивается на сложность реализации, медлительность датчиков, их капризность и невоспроизводимость полученных результатов. Поэтому вместо чисто случайных чисел стали использовать псевдослучайные числа, генерируемые с помощью той или иной программы. Случайность при таком подходе заменяется непредсказуемостью для неосведомленного пользователя: наблюдая некоторое время "хорошую" последовательность псевдослучайных чисел, он не в состоянии предсказать, каким будет следующий член этой последовательности, хотя на самом деле все они вычисляются по - довольно простой формуле. Прежде чем использовать для решения задач тот или иной датчик случайных чисел (табличный, физический или программный), его подвергают разнообразным тестам: на равномерность (или согласие с другим предписанным законом распределения), на независимость и т. д. Наиболее полный анализ алгоритмов генерации псевдослучайных чисел и методов их тестирования имеется в книге [58].
676 Глава 17 Одно из преимуществ метода Монте-Карло заключается в его своеобразной "локальности": этим методом можно, например, искать одну составляющую решения системы линейных уравнений, не интересуясь другими компонентами, или искать значение функции, являющейся решением дифференциального уравнения, в одной точке и т. п. Если, например, трудоемкость прямых методов вычисления определенных интегралов с ростом размерности п пространства переменных возрастает как kn (к — число шагов, на которое разбивается интервал интегрирования по каждой оси), то трудоемкость алгоритма Монте-Карло возрастает как kn/z. Основной недостаток метода Монте-Карло — сравнительно медленная сходимость, для получения более или менее надежных результатов требуется большое число повторений. 17.1. Генерация случайных данных Функция rand используется для генерации псевдослучайных чисел, равномерно распределенных в интервале от 2"53 до 1-2"53 (примерно — [о; i]). Теоретически функция rand позволяет без повторений сгенерировать 21092 псевдослучайных чисел. Обратившись к этой функции без аргумента, мы получаем очередное случайное число. Если у функции задается один скалярный аргумент, то функция rand(n) возвращает квадратную матрицу п-го порядка, элементами которой являются случайные числа из интервала [о; 1]. Функция rand(n,m) возвращает прямоугольную матрицу размерности nxm со случайными числами. Обращение rand (size (А)} позволяет сгенерировать матрицу случайных чисел, размерность которой совпадает с размерностью массива а. Для перехода от чисто дробных случайных чисел к случайным числам из произвольного диапазона [а; ь] достаточно воспользоваться преобразованием a+(b-a)*rand. В большинстве алгоритмических языков существует средство для возмущения датчика случайных чисел, в С и Pascal — это функция или процедура randomize. Она позволяет избежать повторения результатов при многократных запусках программ, использующих датчик случайных чисел. В системе MATLAB тоже имеется аналогичное средство: rand('state',sum(100+clock)) Первый аргумент такого обращения обозначает служебный массив, определяющий состояние датчика случайных чисел. Формирование некоторых полей этого массива в зависимости от даты и текущих показаний машинного таймера приводит к случайной перенастройке параметров, влияющих на работу программы генерации случайных чисел.
Метод Монте-Карло 677 Состояние датчика случайных чисел можно сохранять и восстанавливать с помощью следующих обращений: s = rand('state');% запоминание состояния в массиве s rand{'state',s) % восстановление состояния по массиву s rand('state',0) % восстановление начального состояния датчика Функция randn позволяет генерировать случайные числа, распределенные но нормальному закону со следующими параметрами: П среднее значение случайной величины равно о; О дисперсия a2=i; П средняя квадратическая ошибка (стандарт) о=1. Форматы обращения к функции randn такие же, как и к функции rand. Если вам потребуются случайные числа, распределенные по нормальному закону со смещенным центром m и заданной дисперсией s, то достаточно воспользоваться преобразованием тч-sqrt (s)*randn. Кроме функций rand и randn, MATLAB предлагает и другие функции, с помощью которых можно создавать различные случайные объекты. Для генерации случайных перестановок из целых чисел 1, 2, ..., п используется функция randperm(n): » p=randperm(6) Р = 2 4 3 6 5 1 Целую галерею матриц с различными свойствами позволяет генерировать функция gallery. В ее состав входит и несколько матриц, элементы которых выбираются случайным образом. 17.2. Элементы математической статистики В математической статистике используются различные числовые характеристики случайных величин. Различают генеральные и выборочные характеристики. Первые относятся ко всей (обычно бесконечной) совокупности значений случайной величины, их можно найти только путем теоретических рассуждений и аналитических вычислений. Характеристики второго типа находятся путем обработки наблюдений за случайной величиной. Наиболее важными характеристиками являются среднее значение и дисперсия. Генеральное среднее обозначим а, генеральную дисперсию — о2.
678 Глава 17 - i-B х N . 1=1 Выборочное среднее по выборке [xi, х3, .. ., xN]: N выборочная дисперсия: В методе Монте-Карло используются выборки одинаково распределенных случайных величин с конечными дисперсиями, для которых известно, что величина ———— при больших n имеет распределение, близкое к станет дартному нормальному. Это позволяет оценить величину отклонения выборочного среднего от генерального: для любого вещественного к верно соотношение Р |х - а| < к-р=г = Ф(к). 2 Г t2/ Здесь Ф(к)=-?= е /2dt — один из вариантов интеграла вероятностей. Его о значение в данном контексте называют доверительной вероятностью. Чаще всего берут: П к=з — тогда доверительная вероятность равна 0.997 (правило "трех сигм"); П к=1.96 — тогда доверительная вероятность равна о. 95; П к=о .6745 — тогда доверительная вероятность равна о. 5. Если зафиксировать к (и тем самым доверительную вероятность Ф(к)), то с ростом числа наблюдений N верхняя граница отклонения выборочного среднего от генерального среднего будет стремиться к нулю с вероятностью, сколь угодно мало отличающейся от 1. Скорость сходимости метода Монте- Карло невелика, она пропорциональна -;=, т.е. для уменьшения погреш- VN ности, скажем, в 10 раз надо увеличить число испытаний в 100 раз. 17.3. Линейная интерполяция в многомерном кубе Рассмотрим такую задачу. Пусть для функции f (xi,x2,...,xn) известны лишь ее значения в вершинах е единичного куба е", т. е. при Xi=o или 1. Требуется
Метод Монте-Карло 679 путем линейной интерполяции найти значение функции в произвольной точке (xi, х2, ..., хп), лежащей внутри или на границе единичного куба. Формулы линейной интерполяции: при n=i: f (xi) = (i-xi)-f <0)+xi-f (i), при n=2: f (xl,x2) = (l-xl)-(l-x2)-f {0,0}+xl-(l-x2)-f (1,0)+ + (l-xl)-x2-f (0,l)+xl-x2-f (1,1) И Т. Д. Проблема заключается в том, что количество слагаемых каждой такой формулы равно количеству вершин куба еп, т. е. 2", и уже при п=ю становится больше юоо. Идея упрощения заключается в том, чтобы использовать не все 2П вершин, а лишь какие-то из них, но делать это не один раз, а несколько, используя всякий раз новый набор вершин, взятых случайным образом. Результаты по всем использованным случайным наборам вершин усредняются. Более конкретно метод Монте-Карло для интерполяции в многомерном кубе выглядит так. Пусть дана точка (xj, хг, ..., хп)еЕг'. Построим случайный вектор e=(el,e2,...,en), компоненты которого принимают только значения о и 1 с заданными вероятностями: р(е,=0)=1-хь p(ei=i)=Xi, Это можно сделать, ВЫПОЛНИВ команды r=rand(l,ri) и е=(г<=х). Значение функции f (хг, х2,...,х„> = Mf (ei,ei,...,en) (среднее значение функции в случайных вершинах единичного куба e=(ei,ei,...,en) при повторении эксперимента). Рассмотрим пример 17.1. ! Пример 17.1. Линейная интерполяция в многомерном кубе ;'' .¾5¾ ,,Шф^^ЖШ^Ц Определим функцию, f, значение которой в любой вершине единичного куба ег- равно квадрату веса этой вершины (весом o-i-вектора называется количество входящих в него единиц). На рис. 17.1 для случая п=2 приведены значения функции в вершинах единичного квадрата, а также линии уровня функции f (Xi,x2)=xi+x2+2-xi-x2, полученной путем линейной интерполяции при указанных значениях в вершинах (взяты уровни с=1/4:1/4:15/4). function progl7_l Xmin=0; Xmax^l; h=0.1; axes ('Xlim',[Xmin-h Xmax+h],'Ylim', [Xmin-h Xmax+h)); axis equal; hold on; x=[0 0 1 1 0]; y=[0 1 1 0 0J; plot(x,y,'к-'); text (0.03,-0.05,'f(0 0)=0'); 2л Зак. «59
680 Глава 17 text (0..03,1. 05,'f (0 1)=14,- text(1.03,-0.05, 'f(1 0)=1')? text(1.03,1.05,'f(1 1)=4'); % уравнение xl+x2+2*xl*x2=c for c=l/4:l/4:l xx=0:0.05:c; yy=(c-xx)./(l+2*xx); plot(xx,yy); end for c=5/4:1/4:15/4 xx=[(c-l)/3:0.05:l 1]; yy= (c-xx) . / (l+2*xx) ,- plot(xx,yy); end xlabel('xl'); ylabel('x2' •); title ('Единичный квадрат с линиями уровня', •FontName','Courier'); 1 0.8 0.G 9J 0-4 0.2 0 - . - ■ -0.2. ( Единичный квадрат с линиями уровня .. f(0 1)=1 \ XVXXVxSSSS^ \\XNvyxvnN4 \\\v^^ v^^§ v^§^ f(oo)=q f(1 1)=4 ГА/Г -.,5 iff 1 1¾; f(10)=1 ";/"■ ] 0:2 0.4 0.6 0.8 1 .-,1,2 xl ' •'" ':'" ■ Рис. 17.1. ^циничный квадрат Ниже приводится текст функции rand interp, выполняющей случайную интерполяцию. Ее первым входным параметром является vert_func —
Метод Монте-Карло 681 функция, вычисляющая значение в произвольной вершине единичного куба е. Единственный аргумент функции vertfunc — вектор, содержащий координаты вершины. Остальные входные парамегры rand_interp это: х — вектор координат заданной точки в кубе и n — количество случайных наборов вершин куба. Выходные параметры: Mf — выборочное среднее значение функции по всем вершинам всех случайных наборов вершин, Df — выборочная дисперсия. function [Mf,Df] = rand_interp(vert_func,-x,N) sumF=0 ; sumD=0; for s=l:N r=rand[size(x)); e=(r<=x); fe=feval(@vert_func,e}; sumF=sumF+fe; sumD=sumD+feA2; end Mf=sumF/N; K2=sumD/N; D.f=M2-MfA2; Приведенная ниже рекурсивная функция unitcube дает точное решение задачи об интерполяции в единичном кубе. Первые два ее входных параметра те же, что у randinterp, третий аргумент к — текущая глубина рекурсии. При обращении следует задавать k=i. function f=unix:_cube (vert_func, x, k) if k>length(x) f=feval(@vert_func,x); elseif (x(k}=0) | (x(k)==l} f=unit_cube (@verx:_func,x, k+1) ; elseif (0<x(k)} К (x(k)<l) y=x; y(k)=0; fO=unit_cube(Gvert_func, y, k+1); y(k}=l; fl=unit_cube(@vert_func,y,k+1); f=(l-x(k))*fO+x(k)*fl; end
682 Глава 17 В качестве vertfunc взята функция weight2, вычисляющая квадрат веса вершины. function w2=weight2(е) w=sum(e); w2=w~2; Для проведения машинных экспериментов была использована следующая программа: % Rand_interp_tst х=[0:.5 0.5] %х=[0.5 0.5 0.5 0.5 0.5] %х=(0.5 0.5.0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5] %х=0.1:0.1:1.0 N=100; iMf,Df]=rand_interp(@weight2,x,N); k=l; fc=unit_cube(@weight2, x, k); s3=3*sqrt(Df/N); d=abs((Mf-fc)/fc); [Mf fc s3 d] % вывод результатов Для желающих воспроизвести эксперименты отметим, что перед их началом была выполнена команда rand с state', 0), все б экспериментов проводились один за другим в указанном порядке. В описании результатов экспериментов используются следующие обозначения: П х — заданная точка; О Mf — приближенное значение функции; П 1 с — точное значение функции; П s3 — "три сигма"; О d=|Mf-fc|/fc — относительная погрешность. Количество повторений во всех случаях было n=ioo. Следует заметить, что это значение, принятое также и в последующих машинных экспериментах, является очень маленьким и годится только для иллюстративных примеров. Для более серьезных целей следует брать N на два-три порядка больше. Результаты этих экспериментов описаны ниже. При х=ю.5 0.5] получено: Mf=1.53, fc=1.5, s3=0.4559, d=0.02.
Метод Монте-Карло 683 В соответствии со сделанной выше оценкой генеральное среднее с вероятностью 0.997 лежит в интервале [1.07; 1.99]. Видим, что для столь высокой доверительной вероятности этот интервал слишком широк. Если уменьшить коэффициент доверия до 0.5, то интервал сузится до [1.42; 1.63], но все еще останется достаточно широким. Реальная точность интерполяции по методу Монте-Карло, характеризуемая величиной d, гораздо выше. При втором эксперименте с тем же х получилось: Mf=1.42, fc=1.5, s3=0.4 413, d=0.0533. Третий эксперимент с х= [о.5 о.ь 0.5 0.5 0.5] дал следующие результаты: Mf=7.41s fc=7.5, s3=1.9196, d=0.Q12. В четвертом эксперименте с х=[0.5, о.5,...] были получены следующие значения: М£=29.22, £с=27.5, s3=4.4 510, d=0.0625. Пятый и шестой эксперименты проводились с вектором x=o.i:0.. 1:1.о: Mf=30.38, fc=31.9, 53-4.1957, d=0.0476. Mf=31.66, fc=31.9, s3=4.4065, d=0.0075. Замечание 1 Конечно, при n=length(x)=2 (эксперименты 1 и 2) применение метода Монте- Карло нецелесообразно: гораздо проще вычислить значение функции по формулам, приведенным выше. Однако при п=5 (эксперимент 3) такие формулы еще надо вывести (они содержат 32 слагаемых), а при п=10 и п=11 (эксперименты 4—6) формулы содержат соответственно 1024 и 2048 слагаемых, что существенно больше, чем количество повторений N=100, дающее вполне удовлетворительные результаты. Замечание 2 Относительная погрешность вычислений по методу Монте-Карло во всех экспериментах ни разу не превысила 0.0 625. 17.4. Вычисление кратных интегралов Простейшая формула вычисления определенного интеграла методом Монте- Карло: J f(x)dx = ——^flx,,, где случайные числа xi равномерно распределены в интервале [а; ь]. В многомерном случае область интегрирования gcr'1, которую будем считать ограниченной, необходимо заключить в n-мерпый прямоугольный паралле-
684 Глава 17 лепипед ai<xi<bi. Для генерации случайных точек х, равномерно распределенных в этом параллелепипеде, можно воспользоваться командой х=а+(Ь-а).*rand (1, п) Здесь a=[ai...an], b=[bi...bn] и rand(i,n) — векторы-строки, операция .* — покомпонентное умножение строк. Если сгенерировать n случайных точек х в этом параллелепипеде и обозначить через ng количество точек xeG, то "объем" области m(G)=m(nn) *ng/n, где объем параллелепипеда т(Пп) = (bi-ai) *...* (Ьг-аГ1),. а интеграл m(G) XjEG ( Замечание J Методом Монте-Карло можно легко найти интегралы по одной и той же области сразу от нескольких функций — для этого надо просто накапливать суммы £fk (xi) для всех нужных функций fk. Рассмотрим пример 17.2. Пример 17.2.]Ищефирование.м;^одом,МокгеУ<арло..'" /^к'т-^Г ?ЙЙ«й^,'^v. I Найдем методом Монте-Карло объем v и положение центра тяжести ho однородного шарового сегмента. Для удобства будем считать, что его "южный полюс" лежит на плоскости х3=о, а отсекающая плоскость ей параллельна. Обозначим радиус шара г, высоту сегмента h. Тогда неравенства, задающие шаровой сегмент х? + у?г + х3г < 2 ■ г ■ х3, х3 < ь. Его объем v = ГГГ - яь 2^^3 1 высота центра тяжести над плоскостью х3=о G Здесь интегралы берутся по области, задаваемой неравенствами, другие две координаты центра тяжести — нули. Исходными данными для вычислений являются: □ радиус круга, лежащего в основании шарового сегмента r0 = V2rh - ь2; □ параллелепипед, включающий шаровой сегмент и задаваемый неравенствами: al<xl<bl, а2<х2<Ь2, аЗ<хЗ<ЬЗ, ГДе al=a2=-r0, а3=0, Ы=Ь2=гО, b3=h.
Метод Монте-Карло 685 Из этих данных можно сформировать векторы a=[-r0,-r0,0], b=[rD,r0,h] и с помощью следующей программы вычислить параметры шарового сегмента: function [V,MhO,DhO] = spherical_segment(r,h,N) sumF=0; sumDf=0 ; NG=0; r0=sqrt(h*[2*r-h)); a=[-rO,-rO,0]; b =[r0, rO,h]; VP=4*rCT2*-h; for s=l:N x=a+(b-a).*rand(size(aJ J; if (х(1)Л2+х(2)Л2+х(3)"2<=2*г*х(3)) & (x(3)<=h) NG=NG+1; fx=x(3); sumF=sumF+ f x; .sumDf =sumDf+fхЛ2 ; end end V=VP*NG/N; MhO=sumF/NG; M2=sumDf/NG; DhO=M2-MhO"2; Для вызова данной функции и вычисления точных значений vprec и норгес использовалась следующая программа: % Spher_segm_tst rand['state' ,0) ; r=10; h=r; N=100; [V,Mh0,Dh0] = spherical_segment(r,h,N) Vprec.=pi* {r-h/3) *пЛ2 H0prec=h*(2*r-0.75*h)/(3*r-h) s3-3-sqrt(DhO/N) Для полусферы (h=r) радиуса г=ю при n=ioo получены следующие результаты: v=2320, мьо=5.8081, s3=o.708. Последнее означает, что с доверительной вероятностью 0.997 истинная высота центра тяжести находится в диапазоне [5.100; 6.516]. Для сравнения точные значения: vprec=2094.4, норгес=б.25. Заметим, что высота центра тяжести, найденная методом Мон-
686 Глава 17 те-Карло, достаточно точна, относительная погрешность ее вычисления 5н равна 0.07. Точность вычисления объема несколько хуже: относительная погрешность 5v равна о. и. В соответствии с замечанием нетрудно было бы одновременно найти и какую-нибудь другую характеристику шарового сегмента, например, момент инерции. 17.5. Решение уравнений в частных производных Рассмотрим решение методом Монте-Карло дифференциальных уравнений в частных производных. Для примера возьмем хорошо известное уравнение Лапласа (считаем, что размерность пространства п=2): Эх* + Эх* Это уравнение описывает многие скалярные физические поля: П температурное поле в изотропной пластине при отсутствии источников и поглотителей тепла; П потенциал скорости установившегося плоского течения несжимаемой жидкости; □ потенциал электростатического поля в области, не содержащей зарядов; □ потенциал ньютонова гравитационного поля в области, не содержащей тяготеющих масс. Решение и этого уравнения ищется для любой точки (х;, х2) определенной области g пространства R2. Должны задаваться условия в каждой точке границы области g одного из следующих видов: П значение функции и; П значения производных 1-го порядка функции u по xi и/или х2; П линейная комбинация значений производных и самой функции. Функции, удовлетворяющие уравнению Лапласа, называются гармоническими. Основное свойство гармонической функции: ее значение в любой внутренней точке области равно среднему арифметическому по окружности любого радиуса с центром в этой точке, не пересекающей границу области. На этом основан метод Монте-Карло для решения уравнений Лапласа, называемый методом случайных блужданий. Его суть, вкратце, такова: начиная с точки х0, в которой мы хотим найти значение функции и, строится последовательность случайных точек xD, xi, хг, ..., называемая случайной траекто-
Метод Монте-Карло 687 рией. Когда траектория достигает границы, фиксируется заданное граничное значение функции и в этой точке (мы ограничимся граничными условиями 1-го рода), и начинает строиться другая случайная траектория из точки хо, и т. д. Все зафиксированные граничные значения суммируются. После построения достаточно большого количества траекторий сумма делится на число траекторий, полученное среднее значение принимается за значение функции и(хО). Кроме среднего значения можно также найти дисперсию и оцепить полученный результат с помощью критерия "трех сигм". Варианты метода случайных блужданий отличаются друг от друга способом построения случайной траектории. Для каждого из них доказано, что выход на границу ограниченной области произойдет за конечное число шагов. Простейший вариант, который пригоден только для выпуклой области, строит одношаговую траекторию (двухточечная схема). Он заключается в том, что из начальной точки проводится луч, угол луча с осью Ох\ — случайная величина, равномерно распределенная в интервале (о; 2тс). Точка xi пересечения луча с границей области — последняя точка случайной траектории. Рассмотрим пример 17.3. ! Пример 17^3. Метод Монте-Карло для решения ура!вне.ний в нартных*^-^-. | ПРОИЗВОДНЫХ .^ tw-J.-■*«-■ .1 ,. .,.. .- -у ._ *-!.__ ;ч.^ ^- ^ | В качестве области g возьмем единичный квадрат, ограниченный прямыми Xi=o, xi=i, х2=о, х2=1. Граничные условия примем такие: на сторонах квадрата, лежащих на осях координат, граничное значение и=0, на двух других сторонах граничные значения задаются линейными функциями: и=х2 при xi=i, u=xi при х2=1. Значение в любой точке границы можно представить как и=х!*х2. Функция и, если продолжить ее на весь единичный квадрат (а фактически — на всю плоскость), удовлетворяет уравнению Лапласа. Это позволяет сравнивать решение, полученное методом Монте-Карло, с точным, вычисленным по формуле u=xi*x2. Функция, реализующая метод случайных блужданий по двухточечной схеме, имеет вид: function [Mu,Du]=laplas_two_points(xO,N) 5umU=0; sumD=0; twopi=2*pi; for i=l:N phi=twopi *rand; cs=cos(phi);
688 Глава 17 sn=sin(phi); omega=[cs sn]; t=-xO. /omega; if abs(t(l))<=1 T0=t(l); else T0=t(2); end t=(l-xO)./omega; if abs(t(l))<=1 Tl=t (lb- else Tl=t(2); end if T0>0 T=T0; else T=T1; end xbord=x0+T*omega; ubord=bordfunc(xbord); sumU=s umU+ubord ; зитО=гитО+иЬогдл2; end Mu=sumU/N; M2=sumD/N; 0и=М2-МГл2; Здесь bordfunc — функция, вычисляющая граничные значения (без контроля принадлежности точки границе области). function ub=bordfunc(х) ub=prod(x); Возьмем х0=[0.5 0.5], имеем точное значение иргес=0.2500. При 4-х запусках программы были получены следующие результаты (всюду n=io.o): Mu=0.20"61, За=.0.0830, 5=0.1757. Mu=0.2447, 30=0.0920, 5=0.0213. Mu=0.1873, 30=0.0867, 8=0.2507. Mu-0.1974, 30=0.0853, 5=0.2103.
Метод Монте-Карло 689 Здесь обозначено: □ Ми — приближенное значение гармонической функции; П Зо=з ■ JD^ —доверительный интервал; П 5=|Mu-uprec| /Uprec — относительная погрешность. Анализ результатов показывает, что во всех случаях Upr.ec укладывается в интервал Mu±3o, относительная погрешность варьируется от 2% до 25%, причем приближенное значение во всех 4-х случаях меньше точного. Для другой точки х0=[0.1 0.9] результаты получились гораздо хуже: в 4-х просчетах относительная погрешность принимала значения от 18% до 63%, хотя по-прежнему во всех случаях иргес=о.09 укладывалось в интервал ми+за. Рассмотрим пример 17.4. ЙП^)й©р^^Мё;^.с1^^йнь1хблуждшйЩ с1тквадр^тной реткой ^.¾^ I ;.йП"К".ЬЙ:.Т,., В другом варианте метода случайных блужданий используется квадратная сетка с некоторым шагом h, так что координаты узлов xi=i-h, x2=j-h (по- прежнему считаем, что область g — единичный квадрат). Случайная траектория состоит из узлов сетки, переход от узла (i,j) к любому из соседних с ним узлов (i+i,j), (i-i,j), (i,j+i) и (i,j-l) происходит с вероятностью 0.25, обрыв траектории возникает при выходе на границу. В функции laplas_grid, реализующей этот метод, параметр L — число шагов h, укладывающихся на стороне квадрата, так что h=i/L. function [Mu,Du]=laplas_grid(xO,LfN) sumU=0; sumD=0; h=l/L; for k=l:N i=round(x0(1) +L); j=round(x0(2)*L); while (i~=0) & (i~=L) & (j~=0) £ (j~=L) r=rand; if r<0.25 i=i+l; elseif r<0.5 i=i-l; elseif r<0.75 else end end
690 Глава 17 xfoord=[i*h j*h] ; ubord=bordfunc(xbord); sumU=sumU+ubord; sumD=sumD+ubord',2; end Mu=sumU/N; M2=sumD/N; Ои=М2-Мил2; Возьмем хО-юл 0.9], имеем uprec=o.09. При 4-х запусках программы были получены результаты (всюду n=ioo, l=io): Mu=0.0800, Зст=0.0285, 6=0.1111. Mu=0.0960, 30=0.0400, 5=0.0667. Mu=0.0830, 30=0.0363, 8=0.0778. Ku=0.0870, За-0.0419, 5=0.0333. Анализ результатов показывает, что во всех случаях ирсес=0.09 укладывается в интервал ми±зо, относительная погрешность варьируется от 3% до 11%, причем приближенное значение в двух случаях меньше точного, а в других двух — больше. Рассмотрим теперь пример 17.5. рЬр^нер: 17:5. Метод случайных блужданий по.i^gRae^^c^^'ijg^^T^'^-l Третий вариант метода случайных блужданий называется блужданием по сферам (в двумерном случае получается по окружностям). Случайная траектория строится так. Находясь в очередной точке траектории х, проводим сферу (окружность) некоторого радиуса r с центром в этой точке, которая не пересекает границу области. На ней берем следующую случайную точку х ■, распределение точек на сфере (окружности) равномерное. Процесс прекращается, когда очередная точка оказывается достаточно близко к границе. Чтобы как можно скорее выйти к границе, радиус сферы (окружности) всякий раз будем брать максимально возможный, т. е. равный расстоянию от центра до границы. Вспомогательна;! функция nearstborder ищет радиус r и точку границы xborder, ближайшую к центру. function [R,xborder]=nearst_border(x) хх=[х 1-х]; R=min(xx); if R=x-(1) xbprder=[0 x(2)];
Метод Монте-Карло 691 elseif R==x(2) xborder=[x(l) 0]; elseif R=l-x(l) xborder=[l x(2)]; else xborder=[x(l) 1]; end В функции lapiascircie, реализующей метод случайных блужданий по окружностям, параметр г — расстояние точки до границы, при котором последняя считается достигнутой. function [Mu,Du]=laplas_circle(xG,r,N) sumU=0; sumD=0; twopi=2*pi; for i=l:N x=xO ; while 1 [R,xbord]=nearst_bord(x); if R<r break end phi=twopi * rand; cs=cos(phi); sn=sin(phi); omega=[cs sn]; x=x+R* omega; end ubord=bordf utic (xbord) ; sumU=sumU+ubord; sumD=sumD+ubordA2; end Mu=sumU/N; M2=sumD/N; Du=M2-MuA2; Возьмем x0=[0.i 0.9], имеем uprec=o.09. При 4-х запусках программы получены результаты (всюду n=ioo, г=о.05): Ми=0.0742, Зст=0.0366, 5=0.1751. Mu=0.0S56, Зо=0.0262, 5-0.3810.
692 Глава 17 Mu=0.0981, За=0.0377, 5=0.0900. Mu=0.0664, Зо=0.0281, 5=0.2620. Анализ результатов показывает, что иргес=о.оэ укладывается в интервал Mu+Зст во всех случаях, кроме второго, относительная погрешность варьируется от 9% до 38%, причем приближенное значение в трех случаях меньше точного, а в одном — больше. Общий вывод по трем реализациям метода случайного блуждания для решения уравнения Лапласа (не очень основательный ввиду недостаточности экспериментального материала): наилучшие результаты дает метод блуждания по квадратной сетке. Применим этот метод для решения уравнения Пуассона (пример 17.6): _- + -_ = f(x,y). ох; the. Для этого уравнения метод Монте-Карло несколько видоизменяется: вдоль траектории суммируются значения функции f и,у), взятые с коэффициентом — o.25-h2 (h — шаг сетки). Когда траектория достигает границы, к сумме добавляется граничное значение функции и. ; Пример 17.6. Решение уравнения Пуассона методом блуждании ~Я . ] ; по квадратной сетке й . *ч* - - , .-. Ц»ф:~.< $*-\ *..ю;.% ■*'*■- \ Для примера в качестве области опять возьмем квадрат, граничные условия будем считать однородными (т. е. нулевыми), правую часть примем f (х, у) =-1. В такой постановке эта задача имеет интересную физическую интерпретацию: функция и(х,у) (решение уравнения Пуассона) представляет собой скорость течения вязкой жидкости в каждой точке нормального сечения трубы. Нулевые граничные значения описывают прилипание вязкой жидкости к стенкам трубы. Физический смысл правой части уравнения Пуассона (у нас — константа, равная -1) — это градиент давления вдоль трубы. Для случая трубы с квадратным сечением точное решение уравнения Пуассона выражается в виде двойного ряда Фурье. При желании можно было бы сравнить с ним решение, подученное методом Монте-Карло. Вместо этого мы сравниваем его с решением, полученным классическим методом сеток (см. разд. 12.8.4). В функции poissongrid, построенной, в основном, по образцу функции lapiasgrid, реализующей метод случайных блужданий по квадратной сетке, смысл входных и выходных параметров тот же. Случайной величиной, математическое ожидание и дисперсию которой находит функция poisson_grid, является сумма, накопленная вдоль отдельной траектории (в программе — переменная т). Функция right_func вычисляет значение пра-
Метод Монте-Карло 693 вой части (в примере эта константа равна -1), функция bordfunc вычисляет граничное значение (в примере эта константа равна о). function [Mu, Du]= poisson_grid(xO,L,N) sumU=0; sumD=0,- h=l/L; coeff=-0.25*h"2; for k=l:N i=round(xO(l)*L); j=round(xO(2)*L); T=0; while (i~=0) s (i-=L) & (j~=0) & (j~=L) sumP=sumP+l; r=rand; if r<0.25 i=i+l; elseif r<0.5 i=i-l; elseif r<0.75 else end x=[i j]*h; f=coeff*right_func(x); T=T+f; end T=T-f; ubord=bordfunc(x); T=T+ufoord; sumU=sumU+T; sumD=sumD+T"2; end Mu=sumU/N; M2=suuiD/N; Du=M2-Mu~2; Возьмем x0=[0.5 0.5]. При 4-х запусках программы получены результаты, приведенные ниже (всюду n=ioo, l=io). Для сравнения, значение Ми, найденное методом сеток (см. разд. ]2.8.4), равно о.0731. С учетом этого значения выбиралась относительная погрешность 5. Ми=0.0743, 30=0.0160, 6=0.0164. Ми=0.0725, Зо=0.0154, 6=0.0082.
694 Глава 17 Mu=0.0660, Зо=0.0187, 5=0.0971. Mu=0.0723, 30=0.0148, 6=0.0109. Возьмем х0=[0.1 0.9]. При 4-х запусках профаммы получены результаты (всюду ы=юо, ь=ю). Метод сеток для этих же данных дал ми=о.0128. Ми=0.0057, 30=0.0047, 6=0.5547. Ми=0.0124, 30=0.0119, 6=0.0313. Ми=0.0122, 30=0.0068, 5=0.0469. Ми=0.014'8, 30=0.0081, 5=0.1563. Значения Ми были вычислены и для всех остальных внутренних точек решетки (для фаничных точек взято значение ми=0), после чего были построены линии уровня ми для значений v=o.oi:0.oi:0.07 (рис. 17.2). function poisson__graph rand ('state',0); N=100; L=10; Xmin=0; Xmax=l; h=0.1; X0=Xmin:h:Xmax; Ymin=0; Ymax=l; Y0=Ymin:h:Ymax; [X Y]=meshgrid(X0,Y0>; s=size(X); Z=zeros (s.) ; for i = 2:s(1)-1 for j = 2:s (2)-1 xO = lX(i,j); Y(i,j)]; [Mu, Du] = poisson_grid(xO,L,N); Z(i,j) = Mu; end end V=0.01:0.01:0.07; contour (X, Y, Z,V) ; hold on; grid; xlabel('xl') уlabel('x2') title. {'Решение уравнения Пуассона методом Монте-Карло',... 'FontName',•Courier')
Метод Монте-Карло 695 Рис. 17.2. Линии уровня в задаче Пуассона Рекомендуется сравнить этот рисунок с более "регулярным", приведенным в разд. 12.8.4, где решение той же задачи найдено методом сеток. 17.6. Моделирование случайных процессов Иногда метод Монте-Карло позволяет изучать процессы, в которых большую роль играет случайность и для которых затруднительно построить математическую модель стандартными методами теории вероятностей. Подход заключается в том, что строится имитация изучаемого процесса и многократно разыгрывается с использованием датчика случайных чисел (пример 17.7). { Пример 17.7: Прогнозирование случайного процесса ■'-- u *-*■*'''\%&^г1У. W'4 Рассмотрим случайный процесс, являющийся примером процесса рождения и гибели (скорее "гибели и восстановления"). Мы построим модель, с помощью которой можно делать прогнозы о ходе этого случайного процесса и подбирать значения параметров, обеспечивающие его устойчивость. Время, определяющее течение процесса, будем считать дискретным, так что все величины, характеризующие состояние процесса, маркируются моментами времени t=i, 2, ... Перечислим эти величины.
696 Глава 17 В цехе имеется п однотипных станков, из них в любой момент t исправных mt, остальные n-mt — неисправные. Любой исправный станок к следующему моменту с вероятностью р может выйти из строя, т. е. стать неисправным. Имеется и рабочих, каждый из которых может заниматься ремонтом одного неисправного станка. В любой момент времени в ремонте находится rc=min(u,n-int) станков и любой из них к следующему моменту с вероятностью q может быть отремонтирован, т. е. стать исправным. В функции workshop описанные процессы моделируются методом Монте- Карло. function m=workshop(n,u,p,q,re) X=0; for i=l:m if rand<p m=m-l; end end r=min[[u n-m]); Y=0; for i=l:r if rand<q Y=Y+1; end end m=m+(Y-X); Возьмем n=ioo, m=ioo, u=io, p=0.05, q=o.2. Возвратим датчик случайных чисел в начальное состояние — rand( 'state' , 0) и, выполнив 99 раз команду m=workshop(n,u,p,q,m), получим 100 значений переменной т". 100, 95, 90, 88, 87, 84, 82, 78, 77, 77, 72, 71, 73, 73, 72, 67, 63, 62, 58, 59, 58. 56, 53, 53, 52, 49, 48, 47, 47, 48, 45, 41, 39, 41, 41, 40, 41, 42, 42, 43, 44. 44, 44. 45, 42, 45, 48, 47, 46. 48, 49, 47, 46, 43, 41, 40, 39, 37, 38, 36, 34, 34, 35, 36, 31, 33, 32, 32, 34, 35, 34, 31, 33, 33, 35, 39, 41, 42, 41, 41, 43, 42, 41, 41, 39, 40, 40, 43. 43. 43, 45, 46, 42, 38, 40, 38, 39, 38, 35, 35. Видим, что количество исправных станков медленно, но верно убывает, так что за 99 тактов их осталось примерно треть. Очевидно, 10 ремонтников недостаточно для поддержания работоспособности цеха. Попробуем теоретически оценить количество ремонтников, необходимое для того, чтобы процесс был стационарным, т. е. чтобы среднее количество исправных станков оставалось неизменным в течение большого (потен-
Метод Монте-Карло 697 циально неограниченного) числа тактов. Рассмотрим случайную величинух — количество станков, которые за один такт выходят из строя. Если число исправных станков к началу такта было ш, вероятность выхода из строя за один такт любого станка равна р, а выход из строя отдельных станков — независимые случайные события, то математическое ожидание случайной величины х равно тр. Рассмотрим случайную величину y — количество станков, отремонтированных за один такт. Пусть количество ремонтников u&i-m, где n-m — количество станков, неисправных к началу такта. Тогда все неисправные станки находятся в ремонте. Если завершение за один такт ремонта каждого отдельного станка — независимые случайные события с вероятностью q, то математическое ожидание случайной величины y равно (n-m)q. Случайная величина приращение количества исправных станков равна разности y-x, ее математическое ожидание равно (n-m)q-mp. Условие стационарности процесса заключается в том, что это математическое ожидание равно о. Отсюда получаем m(p+q)=nq. Таким образом, стационарное количество исправных станков m0=nq/ (p+q), а количество ремонтников, минимально необходимое для поддержания стационарного количества исправных станков, u>Uo=n-mo=np/ (p+q) - Рассмотрим численный пример. Пусть, как прежде, п=юо, p=o.os, q=0.2. Тогда стационарное значение количества исправных станков mp=tiq/(p+q)=80, минимально необходимое количество ремонтников u0=n- -mo=np/(p+q)=20. Будем считать, что начальное количество исправных станков равно стационарному: m=m0-80, количество ремонтников равно минимально необходимому: u=Uo=20. Зададим randСstate',0) И, ВЫПОЛНИВ 99 раз команду m=workshop(n,..u,p,q,m), получим 100 значений переменной т. 80, 81, 79, 77, 78, 79, 79, 60, 77, 81, В1, 82, 83, 86, 83, 86, 84, 88, 83, 83, 85, 82, 82, 79, 74, 74, 76, 75, 74, 71, 73, 74, 76, 73, 73,' 77, 76, 73, 75, 74, 69, 69, 69, 67, 70, 72, 73, 74, 78, 81, 84, 83, 81,. 83, 84, 85, 88, 78, 78, 78, 77, 74, 76, 78, .83, 82, 83, 82, 84, 82, 77, 78, 80, 7В, 81, 80, 81, 77, 79, 81, 77, 78, 77, 75, 77, 81, 83, 80, 81, 81, 81, 77, 73, 69, 71, 69, 65., 62, 59, 56. Среднее значение, которое легко подсчитать в процессе эксперимента, равно 77.55, оно не так уж сильно отличается от математического ожидания то=80, однако разброс значений случайной переменной т весьма велик: пъах=8В, ^„^=56. Это объясняется тем, что на каждом шаге стартовым значением переменной m является не ее математическое ожидание т0, а то, что получено на предыдущем такте.
698 Глава 17 Более развитая вероятностная модель процесса порчи и восстановления, позволяющая оценить не только математическое ожидание, но и дисперсию (т. е. разброс), основана на аппарате цепей Маркова. Мы ее рассматривать ие станем, а вместо этого проведем еще один вычислительный эксперимент С функцией workshop. Увеличим число ремонтников, взяв и=25 (значения остальных величин оставим прежними). Снова зададим rand С state", о) и получим другие 100 значений переменной ш: 80, 81, 79, 78, 79, 81, 82, 80, 79, 83, 80, 80, 82, 81, 80, 81, 77, 80, 80, 82, 79, 76, 80, 77, 73, 78. 82, 85, 83, 80, 84, 82, 83, 84, 83, 80, 79, 83, 80, 75, 77, 72, 75, 78, 72, 72, 74, 77, 79, 79, 81, 77, 79, 78, 80, 68, 69, 75, 72, 70, 67, 70, 70, 68, 70, 72, 73, 76. 80, 79, 78, 78, 83, 81, 82, 80, 78, 77, 78, 79, 82, 86, 86, 87, 8'7, 80, 78, 78, 83, 73, 75, 78, 75, 78, 75, 78, 74, 75, 82, 82. Среднее значение 78.26 стало немного ближе к математическому ожиданию, разброс несколько уменьшился: itwx=87, itiain=67. Рассмотрим пример 17.8. | Пример 17.8. Имитационная модель матричной игры В разд. 16.3 рассматривалась игра "Жулик" с тремя чистыми стратегиями у каждого участника и с платежной матрицей, воспроизведенной в табл. 17.1 (содержательные наименования стратегий заменены их римскими номерами). Таблица 17.1 I II III I 1 -1 2 II -1 1 -1 III -2 1 0 Методами линейного программирования в разд. 16.3 были найдены: цена этой ипэы v=i/5 и оптимальные смешанные стратегии игроков р=[0 3/5 2/5], q=[2/5 3/5 0]. Теперь построим имитационную модель игры, которая позволит на деле оценить эти и другие стратегии. function v=trickster(p,q,N) R=[l -1 -2 -111 2-1 0];
Метод Монте-Карло 699 sumA=0; P=oumsuzn(p) ; Q=cumsum(q); for k=l:N r=rand; if r<P(l) i=l; elseif r<P(2) i=2; else i=3; end r=rand; if r<Q(l) j-i; elseif r<Q(2) j=2; else j=3; end sumA=sumA+A(i, j) ; end v=sumA/K; Зададим число повторений игры n=ioo, и пусть игроки придерживаются своих оптимальных стратегий. Первый игрок получит выигрыш v=o.2. Пусть первый игрок придерживается той же стратегии р, а второй — стратегии q=[i/3 1/3 1/3]. В этих условиях первый игрок получит выигрыш v=6.42. Вывод: попытка второго игрока отклониться от оптимальной стратегии увеличила его проигрыш. С функцией trickster можно провести и другие эксперименты. 17.7. Случайный поиск Имеются два основных направления применения метода Монте-Карло для поиска минимума функции. Первое направление, которое мы подробно рассматривать не будем, — локальный поиск, во многом аналогичный детерминированному (например, градиентному) поиску, который представляет собой последовательный переход от одной точки к другой, близкой точке. Отличие от детерминирован-
700 Глава 17 иого поиска заключается в том. что каждый шаг делается с той или иной степенью случайности. Например, достигнув очередной точки, делают из нее несколько небольших пробных шагов в случайных направлениях и для перехода к следующей точке выбирают из этих шагов тот, который дат наименьшее значение целевой функции в пробной точке. Если все пробные шаги приводят к увеличению значения функции — минимум достигнут. Второе направление — глобальный поиск, обычно являющийся подготовительным этапом перед локальным спуском (случайным или детерминированным). Этот этап особенно актуален для мпогоэкстремальных функций, когда результат локального поиска кардинально зависит от выбора начальной точки — именно эти точки (при отсутствии информации о "глобальном строении" целевой функции) полезно выбирать случайным образом. Более конкретно этот алгоритм (его иногда называют набросовым) заключается в следующем. На область предполагаемого поиска "набрасывается" некоторое количество случайно выбранных точек хд (i=i, ..., n), затем из каждой точки Xi делается локальный спуск в точку х±'. В качестве точки глобального минимума принимается та точка х**, для которой значение целевой функции f (xi'l минимально: f (х") = min f(x^). i-l N Рассмотрим пример 17.9. I Пример 17.9. Минимизация функции методом Монте-Карло .■"--.■ ,/e%Jf "*"-;: Рассмотрим задачу о минимизации функции, являющейся взвешенной суммой абсолютных величин комплексной переменной z и многочлена 7-й степени w=z (z2+l) (Cz-2)z-hJ) ((z+2)2+4): function y=abspoly7(x,pl,p2) z=coraplex (x (1) , x (2) ) ; w=z+{гл2+1)* ((z-2)л2+4)* ((z+2)л2+4); y=pl*abs(z)+p2*abs(w); Эта функция имеет семь локальных экстремумов, один из них с нулевым значением функции в точке х-[о,-0] — глобальный. Будем исходить из того, что известна область, в которой расположены все локальные экстремумы, — это квадрат 4X4 с центром в начале координат. Определим массив из n пар случайных чисел, равномерно распределенных в этом квадрате: г=-4+8* *rand(2,N). Например, при N=4 получится г =[3.6010 0.8547 3.1304 -0.3483 -2.1509 -0.1121 2.0968 -3.8520]
Метод Монте-Карло 701 В компьютерном эксперименте на этот квадрат было набросано 20 случайных точек, и от каждой из них, как от начальной, был выполнен поиск минимума путем обращения к функции [х,fval]=fminsearch(Eabspoly7,xO, options, pi,p2) (значения коэффициентов в abspoly7 взяты pi=o.oi, p2=o.oi). В табл. 17.2 представлены все найденные локальные минимумы, в последней строке — глобальный минимум. Таблица 17.2 к1 2.0000 2.0000 -2.0000 -2.0000 х2 2.0000 -2.0000 2.0000 -2.0000 fval 0.028 4 0.0284 0.0284 0.0284 xl 0.0000 0.0000 0.0000 | х2 | 1.0000 | -1.0000 1 0.0000 fval 0.0101 D.0101 0.0000 Случайный выбор начальных точек. "£ 4 -" 3 2 ■: 1 Ч 0 т1 -2 -3 -А -4 " -2:. 0 - 2 .4. Б х1 Рис. 17.3. Случайный поиск минимумов На рис. 17.3 представлены линии уровня функции abspoly?, n=20 случайных точек (изображены маленькими кружками), найденные от каждой из
702 Глава 17 них, как от начальной точки, локальные минимумы (изображены большими кружками). Переход от каждой начальной точки к локальному минимуму изображен отрезком прямой. Реально перемещение шло по зигзагообразным траекториям, но их изображение загромоздило бы рисунок. function Rand^search Xmin=-4.5; Xmax=4.5; h=0.2; XO=Xmin:h:Xmax; Y0=X0; axes ('Xlim',[Xmin Xmax],'Ylim',[Xmin Xmax]); axis equal; [X Y]=meshgrid(XO, YO); s=size(X); Z=zeros(s); p]=0.01; p2=0.01; for i = l-.s(l) for j = l:s(2) x = [X(i,j); Y(i,j)]; z = abspoly7(x,pl,p2) ; Z(i,j) = z; end end %M=max(.max(Z)) ; v=D:h:0.9; V=l:10; hold on; contour(X,Y,Z,[v V]); xlabel{'xl'); ylabel('x2'); title ('Случайный выбор начальных точек'f'FontName','Courier'); N=20; r=-4+8*rand(2,N); options = [] ; globalnu.n= [0;0;Inf ]; localmin=zeros(3, N); for j=l:M x0=r<:, j );
Метод Монте-Карло 703 plot ([хО(1)Ь [х0(2)], 'Marker1, '.*, 'MarkerSize', 10); [х,fval]=fminsearch(Sabspoly7,x0,options,pi,р2); localmin (:, j ) = [x; fi/al] ; if fval<globalmin(3) globalmin=[x;fval]; end plot([x(l)1,[x(2)], 'Marker', '.', 'MarkerSize', 20); plot([x0(l) x(l)],[x0(2) x (.2) J ); end localmin' globalmin'
Приложения
Приложение 1 Помощь в системе MATLAB Система MATLAB снабжена довольно подробным справочным файлом, который позволяет получить информацию как по собственно пакету MATLAB, так и по всем его приложениям. Комплект документации, включая файлы в PDF-формате, занимает полный CD-ROM. *Jk Preferences ©General : itl- Fonts [- Colors | i+bCommand Window — Command History IB Editortoebugger \~Ш \ ■ Web i—Current Directory у Workspace - Array Editor - GUIDE l+bFigure Copy Template й-Stmulink Help Preferences i Product tiller ' -iftWw4:-.&:iJi Enabling the product filter allows you to select the products displayed in the Help Navigator. ! Select products... | P Enable product filter ~~ -jfeHelp Product Filter| Select the products to display In the Help Navigator. General p Keep confer P Release Notes P Installation P MATLAB P Excel Link P MATLAB Builder for COM P MATLAB Builder for Excel P MATLAB Compiler P Bioinformatics Toolbox P Curve Fitting Toolbox ^J; Select All ( OK OK J Cancel Clear All j Cancel j Apply h'efp. Help Рис. П1.1. Отбор пакетов расширения, включаемых в текущую справочную базу
708 Приложение 1 Справочная система MATLAB 7 может быть настроена на любой перечень установленных пакетов. Чем меньше пакетов нам понадобится в очередном сеансе, тем меньшей по объему будет сформирована текущая справочная база. И тем быстрее будут находиться интересующие вас термины. Настройка осуществляется по цепочке команд File | Preference | Help (Файл | Предпочтения | Справка). В появившемся диалоговом окне следует отметить флажок Enable product filter (Разрешить фильтр пакетов) и нажать кнопку Select products (Выбор пакетов). В очередном диалоговом окне имеется возможность быстро выделить все установленные на нашем компьютере пакеты (кнопка Select All (Выбрать все)) или метить только те флажки, которые нам понадобятся в ближайшее время (рис. П1.1). Поиск по ключевым словам Существует несколько способов получить ответ по интересующему вас термину. П Набрать в окне Command Window (Окно команд) команду help, задав ей в качестве параметра искомое ключевое слово, например, double: » help double DOUBLE Convert to double precision. DOUBLE(X) returns the double precision value for X. If X is already a double precision array, DOUBLE has no effect. DOUBLE is called for the expressions in FOR, IF, and WHILE loops if the expression isn't already double precision. DOUBLE should be overloaded for all objects where it makes sense to convert it into a double precision value. Ответ по такому запросу будет получен только в том случае, если среди системных файлов MATLAB обнаружит файл double.m. Текст выдаваемой справки представляет собой начальный комментарий соответствующего m-файла. П Набрать в окне Command Window (Окно команд) команду lookfor с искомым ключевым словом Или набором ключевых слов, заключенных в апострофы: » lookfor 'hyperbolic sine' ASINH Inverse hyperbolic sine. SINH Hyperbolic sine.
Помощь в системе MATLAB 709 ASINH Symbolic inverse hyperbolic sine. SINH Symbolic hyperbolic sine. » Ответ по такому запросу содержит имена га-файлов и строки, в которых встречается указанный набор ключевых слов. Искать, например, ключевое слово double по команде lookfor особого смысла не имеет, т. к. встречается оно в довольно большом количестве файлов: ■» lookfor double DBLQUAD Numerically evaluate double integral. HEX2NUM Convert IEEE hexadecimal to double precision number. STR2D0UBLE Convert string to double precision value. DOUBLE Convert to double precision. PNDANIM2 S-function for animating the motion of a double pendulum. PNDANIM3 S-function for animating trie motion of a double pendulum. AX_BLOCK_DCLK Callback file for ActiveX Block's double click event. FINARGDBLE Format an argument into a double array of NaN padded rows. □ Набрать в окне Command Window (Окно команд) команду doc, задав ей в качестве параметра искомое ключевое слово, например, sinh: » doc sinh 1^ Help File Edit View Go -Favorites Desktop Window Help Help H.avi gator _ x .Corielnls§ Imlex|-S«arch | Demm | " —О Begin Here -^ Э> Ф Release Notes '№0 Installation fe^ MATLAB 4 О Getting Started ! 9*-Ф Examples ss-JJll Desktop Tools and Development 1 $-¾ Mathematics | a ©Programming 1 ^1-¾ Graphics зд-IQ 3-D Visualization 1 >) © Creatin Gra hical User Ihterfac :-+-¾ Functions - Gate onca! List i 1 1 as-Desktop Tools and Development b-Mathematics —' Si-Programming and Data Types ijsFiIel/O ^-Graphics Чг-3-Т) Visualization man •v ^■♦O'i i» Tlllffi | snh (MATLAB Fumaions) MATLAB Function Reference sinh Hyperbolic sine of an argument in radians Svntax Y = sinh(X) Description z\ L2 El- The si nh function operates element-wise on arrays.- | The function's domains and ranges include values. All angles are in radians. complex j Рис. П1.2. Результат выполнения команды doc sInn
710 Приложение 1 В результате удачного поиска произойдет переход в окно Help (Справка), в правой части которого будет открыта первая страница документа с указанным заголовком (рис. П1.2). Команды help и doc позволяют организовать поиск информации о термине, у которого мы помним только начальные буквы. После их набора следует нажать клавишу <ТаЬ> и в окне команд появится список терминов, начинающихся с указанной последовательности букв (рис. П1.3). ». help sin Ч1ЯН^1НН ж sine Sincosexp sind single singleMath sinh sinint ▼ Рис. П1.3. Выбор термина по начальным буквам Использование Help-навигатора Левая часть окна справочной системы представлена Help-павигатором, с помощью которого можно сравнительно просто добраться до интересующей вас информации. В нем расположены 4 вкладки: □ Contents (Содержание) — оглавление доступных разделов; □ Index (Указатель) — набор ключевых слов, относящихся к выделенному подразделу и упорядоченных по алфавиту; П Search (Поиск) — окно поиска ключевого слова, набираемого пользователем; □ Demos (Примеры) — оглавление тестовых примеров; На вкладке Contents (Содержание) находится перечень тех пакетов расширений, которые вы отметили при настройке справочной системы (рис. П1.4). Раскрывая соответствующий раздел оглавления и перебирая появляющиеся подразделы, мы можем перейти на нужный фрагмент справочной информации. На рис. П1.5 продемонстрирован переход в кадр ео справкой о магических квадратах. Конечно, такой поиск имеет смысл только тогда, когда мы точно знаем, где находится интересующая нас информация.
Помощь в системе MATLAB 711 Help Havigator Contorts J index | Search I Ретм| ■~ ъ& Release Notes f-ф Installation £-<3* MATLAB :*- 6^ Excel Link f& MATLAB Builder for COM if:-*§> MATLAB Builder for Excel ;ii <3? MATLAB Compiler 'i ^Biomformatics.Toolbox iv ф Curve Fitting Toolbox ■?'■ c^ Fixed-Point Toolbox k: & Fuzzy Logic Toolbox $ Ф Genetic Algorithm and Direct Search T f'-ф Image Processing Toolbox :j"Tsi> Mapping Toolbox it Ф Neural Network Toolbox !;-■ t3> Optimization Toolbox ■•?■ c3*Partial Differential Equation Toolbox ■;i ^ Signal Processing Toolbox i* Ф Spline Toolbox ■ft <ф Statistics Toolbox ■r.-t& Symbolic Math Toolbox £-<& Simuhnk fc <3> Simulink Fixed Point if^Stateflow Т>-Ф Signal ProcessingBIockset 0 Support and Web Services Л1 I ±1 *• *+ \&\k ~3 Tils [Release 14: Begin Нею Begin Here ,¾..^¾ й Release 14 If You Are Upgrading from a Previous Reiease... • Release Notes Summarizes new features, bug fixes, upgrade issues, etc. Video Tutorials Seven audio-video tutorials are the best way to learn the new features in MATLAB. If You Are Using MATLAB for the First Time... At the heart of MATLAB is a new language that you must learn before you can fully exploit its Dower. This isn't as hard as it miaht sound: vpu Zi -iJ I ^.. Л Рис. П1.4. Оглавление из отобранных пакетов расширений Чаще всего нам бывает известен только некоторый термин или сочетание терминов. В этом случае может помочь поиск по индексу (вкладка Index) или по контексту (вкладка Search). На рис. П1.6 отображены результаты поиска словосочетания Magic Squares. В левой части навигатора отображаются названия всех разделов, где был обнаружен заданный контекст. При поиске по индексу разумно набрать в поле ввода Title (Заголовок) первый символ нужного термина, а спустя некоторое время продолжить набор. При этом в справочной базе все разделы отсортировываются по первой букве, что ускоряет последующий поиск. На рис. П1.7 показаны результаты поиска по индексу, равному qr. Вкладка Demos (Примеры) выдает в левой части окна список пакетов расширений, снабженных демонстрационными примерами. Как правило, в каждом из разделов содержится не по одной демонстрационной программе. 34 За* 899
712 Приложение 1 Help JS aydgafcoE: cotttrts | к-йих| s*atch| Овтая| Г "Л Begin Here j Release Notes Installation MATLAB О Getting Stated j] Introduction ^i-Matrices and Arra s 3-1 atnces and Ma. u? S ' _s ■Entering Matrices sum, transpose, and diag -Subscripts The Colon Operator The magicFunctton Э Expressions to-Working "with Matrices "t-More About Matrices and Arr S-Controlling Command Windo'' Й-Graphics ij-j Programming ■p-Creating Graphical Userlnterfac Ti-Desktop Tools and Development Ф Examples -¾ Desktop Tools and Development *• <* C!&|M. THlff-1 Metrites and Ms#c Squares -- M«urtces end Arrays (Getting Started) z] Getting Started Matrices and Magic Squares S Sl- Li MATLAB, a matrix is a rectangular array of numbers. Special meaning is sometimes attached to 1-by-l matrices, which are scalers, and to matrices with only one row or column, which are vectors. MATLAB has otlier ways of storing both numeric and nonnumeric data, but in the beginning, it is usually best to think of everything as a matrix. The operations in MATLAB are designed to be as natural as possible. Where other programming languages work with numbers one at a time, MATLAB allows you to work with entire matrices quickly and easily. A good example matrix, used throughout this book, appeal's in the Renaissance engraving Melencolia I by the German artist and amateur mathematician Albrecht Diirer. Рис. П1.5. Перелистывание оглавления Help Navigator Contorts| Index Search | Demos | Search lor. j MbqIc Squares I Tflla Matrices andMa'eic S.ciuares Matrices and. magic The magic Function pinv Square Systems Arrays Matrices and Array's Other Data Structures Cell Arrays Scripts Flow Control switch and case Creating the User Interface Simple Example MATLAB Func Matrices and Ai MATLAB Func Matrices and Li Matrices and Ai Getting Started Programming Programming Programming Programming Programming Usage Example Stand-Alone Ap ♦» ■» С i a | ft Title: j МаЫсэз and Mage Squares:; Matrices end Arrays (Getting Started) ^»J Getting Started Ш ffl— Matrices and Magic Squares In MATLAB, a matrix is a rectangular array of numbers. Special meaning is sometimes attached to 1-by-l matrices, which are scalers, and to matrices with only one row or column, which are vectors. — MATLAB has other ways of storing both numeric and nonnumeric data, but in the beginning, it is usually best to think of everything as a matrix. The operations in MATLAB are designed to be as natural as possible. Where other programming languages work with numbers one at a time, MATLAB allows you to work with entire matrices quickly and easily. A good example matrix, used throughout this book, appears in the Renaissance engraving Melencolia I by the German artist and amateur mathematician Albrecht Diirer. _____ Рис. П1.6. Поиск контекста
Помощь в системе MATLAB 713 Help; Navigator __ * Conterts Шейк | Saorch I Demos | ; iStiiEtsiiiciii ■ ! ' ii о £. Q B. 3¾ T U. X.W& "r Z. ■ Search hdex tor. |qr Name I Product | ipin Signal Pr... -»■ qrar MATLAB qqplot Statistics... a MATLAB QR decomposition Statistics... QR decomposition Curve Fitt . QR -fecomposition 1AATLAB «- -f С jS'M Tflle: | qr (MATLAB Functions) qr Orthogonal-triangular decomposition Sviitax [Q,R] = qr(A) (/uiZ [Q,R] = qr(A,0) (full fO.R.El = or(A) /full ,j. I I I I and spar: I and spar: i matrices, i Рис. П1.7. Поиск по индексу qr Кнопки-стрелки в верхней и нижней частях кадров помощи позволяют перемещаться вперед и назад по заголовкам разделов или по. кадрам помощи. Кроме того, над правым окном навигатора расположен раскрывающийся список Title (Заголовок), в котором фиксируются разделы, просмотренные во время текущего сеанса. Его можно использовать для повторного входа в один из предыдущих разделов справочной базы (рис. ГЛ.8). Help Mayigatpjr; Conterts | index | Search | Demos | — О Begin Here •< i;)- & Release Notes el t-S* Installation ■k $ MATLAB fji- О Getting Stated ■Introduction -Matrices and Arrays j- Entering Matrices [•-sum, transpose, ani ! Subscripts l-The Colon Operate I '- The magic Functiot- *■ •* С | m i #* THIk | Matrices ornl Magic Squares:: hlertrlces end Atrays (Getting Started) Л41,№11М1-'«ШШ1Ш4и'№1-1Д Mpsrices end Arrey$ (Getl^g Started) CeHing Started:: (GettiTg Started MATLAB Rdeaj£ N; Begirt hfgrc ^_^__^_ zl N In Special meaning is sometimes attached to 1-by-l matrices, which are scalars, and to matrices with only one row or column, which are vectors. MATLAB has other ways of storing both numeric and nonnumeric data, but in the beginning, it is usually best to think of everything as a matrix. The operations in MATLAB are designed to be as natural as possible. Where other programming languages work with Рис. П1.8. Перечень справочных разделов, активизированных в текущем сеансе Поиск функций Для ускорения поиска сведений о функции в файлах помощи предусмотрены два систематизированных каталога — список функций, упорядоченных по алфавиту и расклассифицированных по категориям (Functions — Cate-
714 Приложение 1 gorical List) и общий список всех функций, упорядоченных по алфавиту (Functions ~ Alphabetical List) — рис. Ш.9. Help. Bayi.gatqr. Corterts|m»s| searetiJDOTosl i-O Begin Here '?■■ Ф Release Notes ЧИФ Installation ' ^MATLAB ^1 О Getting Started *■ & Examples 8-(¾ Desktop Tools and Development Environment ■»-© Mathematics S- lb Programming ifi (¾ Graphics :•>■ Щ} 3-D Visualization ?!-© Creatin Gra ical User Interfaces i ;!-1Й Functions — Cate orical List t-Desktop Tools and Development Environment s-Mathematics ^-Programming and Data Types 5 File I/O Ift Graphics &--3-D Visualization ffi Creating Graphical User Interfaces 3jb Functions — Alphabetical List * ■* С ! © ' *» ' T«W. | Fundions - Categorical List ffMTLAB Fimctlnis)_^ MATLAB Function Reference Ш — Functions — Categorical List The MATLAB Function Reference contains descriptions of all MATLAB commands and functions. Select a category from the following table to see a list of related functions. Desktop TjoolsjJid. Development Startup, Command Window, help, editing and debugging, tuning, Рис. П1.9. Поиск функций MATLAB
Приложение 2 Указатель свойств графических объектов В данном приложении приведен указатель свойств графических объектов, используемых в книге. Свойство Раздел ■ALim 7.3 ALimMode 7.3 AlphaData 7.7, 7.7 AlphaDataMapping 7Ji 7J Alphamap 7.2 AmbientLightc.olor 7.3 AmbientStrength 10.2.1 BackFaceLighting- 10.2.1 BackgroundColor 8,8.1.1 BackingStore 7.2 BeingDeleted 8 Box 7.3 BusyAction 7.1, 8 ButtonDownFcn 7.1, 8, 8.1.1 Callback 7.1,8,8.1.1,8.1.3 CallbackObject 7.1 CameraPosition 7.3, 10.13 CameraPosi tionMode 7.3
716 Приложение 2 (продолжение) Свойство Раздел CameraTarget CameraTargetMode CameraUpVector Came raUpVe с to rMode CameraViewAngle CameraViewAngleMode CData CDataMapping Children CLim CLimMode Clipping CloseRequestFcn Color Colormap ColorOrder CoiranandWindowSi ze CreateFcn CurrentAxes CurrentCharacter CurrentFigure CurrentObject CurrentPoint Curvature DataAspectRatio DataAspectRatioMode DeleteFcn Diary DiaryFile 7.3 7.3 7.3 7.3 7.3 7.3 7.7,8,8.1.2, 10.26 7.7, 10.26 7.1, 7.11 7.3 7.3 7.1,8 7.2 7.2, 7.4 7.2, 7.7 7.4 7.1 7.1, 8, 8.1.1 7.2 7.2 7.1 7.1 7.2 7.5 7.3, 7.7 7.3 7.1, 8, 8.1.1 7.1 7.1
Указатель свойств графических объектов Свойство Diffusestrength Dithermap DoubleBuffer DrawMode Echo EdgeAlpha EdgeColor EdgeLighting Editing Enable EraseMode Extent. FaceAlpha FaceColor FaceLighting Faces FaceVertexAlphaData FaceVertexCData FileMame FixedColors FixedWidthFontName FontAngle FontName FontSize FontUnits FontWeight Foreg roundColo r Format FormatSpacing 717 (продолжение) Раздел 10.2.1 7.2 7.2 7.3 7.1 10.2.1 7.5, 10.26 10.2.1 7.6 8 7.4, 7.7 7.6 10.3.1 7.5, 10.26 10.20 10.25 10.3.1 10.27 7.2 7.2 7.1 7.3,8 7.3, 8 7.3,8 7.3,8 7.3,8 8, 8. 1. 1 2.4, 7.1 7.1
718 Приложение 2 (продолжение) Свойство GridLineStyle HandleVisibility HitTest HorizontalRlignment IntegerHandle Interpreter Interruptible InvertHardcopy KeyPressFcn Language. Layer LineStyle LinestyleOrder LineWidth ListBoxTop Margin Ma rker MarkerSize MarkerEdgeColor MarkerFaceColor Max MenuBar MeshStyle Min MinColormap MinorGridLineStyle More Name NextPlot Раздел 7.3 8, 8.3.2 7.1,8 7.6,8,8.1.4 8.3.2 7.6 7.1,8 7.2 7.2 7.1 7.3 7.4 7.3, 7.4 7.3, 7.4 8 7.6 2.6.1, 7.4 7.4 7.4, 10.26 7.4, 10.26 8,8.1.5,8.1.6 7.2 10.2.1 8, 8.1.5,8.1.6 7.2 7.3 7.1 7.2 7.2
Указатель свойств графических объектов 719 (продолжение) Свойство NormalMode ■NumberTitle PaperUnits PaperOrientation PaperPosition PaperPositionMode PaperSize PaperType Parent PlotBoxAspectRatio PlotBoxAspectRatioMode Pointer PointerLocation PointerShapeCData PointerShapeHotSpot PointerWindow Position Projection Recurs ionLimit Renderer RendererMode Resize BesizeFcn Rotation ScreenDepth Screen'Size Selected SelectionHighlight SelectionType Раздел 10.3.1 7.2 7.2 7.2 7.2 7.2 7.2 7.2 7.1, 7.2 7.3 7.3 7.2 7.1 7.2 7.2 7.1, 7.2 7.2, 7.3, 7.3 7.1 7.2 7.2 7.2 7.2, 8.3. 7.6 7.1 7.1 7.1, 7.6 7.1,8 7.2
720 Приложение 2 (продолжение) Свойство Раздел ShareColors ShowHiddenHandles SliderStep SpecularColorReflectance SpecularExponent EpecularStrength String Style Tag TickLength TickDir TickDirMode Title TooltipString Type UIContextMenu Units UserData Value VertexNormals VerticalAlignment Vertices View Visible- WindowB'uttonDownFcn WindowButtonMotionFcn WindowButtonUpF'cn WindowStyle XAxisLocation 7.2 7.1 8, 8.1.6 10.2.1 10.2.5 10.2.1 7.6.8,8.1.5,8.3.7 8.1.1 7.8,8, 8.3.7 7.3 7.3 7.3 7.3 8, 8.1.1 7.1 7.1, 8, 8.2 7.1, 8, 8.1.3 7.1,8 8, 8.1.5 10.3.1 7.6 10.25 7.3 7.1,8 7.2 7.2 7.2 7.2 7.3
Указатель свойств графических объектов 721 (продолжение) Свойство XColor XData XDir XGrid XLabel XLim XLimMode XMinorGrid XMinorTick XScale XTick XTickLabel XTickLabelMode XTickMode YAxisLocation YColor YData YDir YGrid YLabel YLim YLiraMode YMinorGrid YMinorTick YScale YTick YTickLabel YTickLabelMode YTickMode Раздел 7.3 7.4, 7.6, 7.7 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.4, 7.6, 7.7 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3
722 Приложение 2 (окончание) Свойство ZColor ZDir ZData ZGrid ZLabel ZLim ZLimMode ZMinorGrid ZMinorTick ZScale ZTick ZTickLabel ZTickLabelMode ■ZTickMode Раздел 7.3 7.3 7.4, 7.6, 7.7 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3 7.3
Литература и интернет-источники MATLAB 1. Андриевский Б. Р. Избранные главы теории автоматического управления с примерами па языке MATLAB. — СПб.: Наука, 1999. — 467 с. 2. Андриевский Б. Р., Фрадков А. Л. Элементы математического моделирования в программных средах MATLAB 5 и Scilab. — М.: Наука, 200 L — 286 с. 3. Ануфриев И. Е. Самоучитель MATLAB 5.3/б.х. — СПб.: БХВ-Петербург, 2004. - 736 с. 4. Герман-Галкин С. Г. Компьютерное моделирование полупроводниковых систем в MATLAB 6.0. — СПб.: КОРОНА принт, 2001. — 315 с. 5. Глушаков С. В., Жакин И. А., Хачиров Т. С. Математическое моделирование: MathCad 2000, MATLAB 5.3: Учебный курс. — М.: РОДИНА- ФОДИО, 2001.-524 с. 6. Говорухин В. Н., Цибули и В. Г. Компьютер в математическом исследовании: Maple, MATLAB, LaTex. — СПб.: Питер, 2001. — 624 с. 7. Гультяев А. К. MATLAB 5.2. Имитационное моделирование в среде Windows. — СПб.: КОРОНА принт, 1999. — 288 с. 8. Гультяев А. К. MATLAB 5.3. Имитационное моделирование в среде Windows. Практическое пособие. — СПб.: КОРОНА принт, 2001. — 432 с. 9. Гультяев А. К. Визуальное моделирование в среде MATLAB. — СПб.: Питер, 2000. — 430 с. 10. Дьяконов В. П. MATLAB 5.0/5.3. Система символьной математики. — М.: Нолидж, 1999. — 633 с. 11. Дьяконов В. П. MATLAB 6/6.1/6.5 + Simulink 4/5 в математике и моделировании. Полное руководство пользователя. — М.: Солон, 2003. — 576 с. 12. Дьяконов В. П. MATLAB 6/6.1/6.5 + Simulink 4/5. Основы применения. Полное руководство пользователя. — М.: Солон, 2002. — 768 с. 13. Дьяконов В. П. MATLAB 6: Учебный курс. — СПб.: Питер, 2001. — 592 с.
724 Литература и интернет-источники 14. Дьяконов В. П. Simulink 4. Специальный справочник. — СПб.: Питер, 2002. - 528 с. 15. Дьяконов В. П. Справочник по применению системы PC MatLab. — М.: Физматлит, 1993. — 112 с. 16. Дьяконов В. П., Абраменкова И. В. MATLAB 5. Система символьной математики. — М.: Нолилж, 1999. — 633 с. 17. Дьяконов В. П., Абраменкова И. В. MATLAB. Обработка сигналов и изображений. Специальный справочник. — СПб.: Питер, 2002. — 608 с. 18. Дьяконов В. П., Абраменкова И. В., Круглов В. В. MATLAB 5.3. L с пакетами расширений. — М.: Нолидж, 2001. — 1296 с. 19. Дьяконов В. П., Круглов В. В. MATLAB. Анализ, идентификация и моделирование систем. Специальный справочник. — СПб.: Питер, 2002. — 448 с. 20. Дьяконов В. П., Круглов В. В. Математические пакеты расширения MATLAB. Специальный справочник. — СПб.: Питер, 2001. — 480 с. 21. Дэбни Дж., Хартман Т. Simulink 4: Секреты мастерства. — М.: БИНОМ, 2003. - 403 с. 22. Кетков Ю. Л., Кетков А. Ю., Шульц М. М. MATLAB 6.x: Программирование численных методов. — СПб.: БХВ-Петербург, 2004. — 672 с. 23. Кондратов В. Е., Королев С. Б. MATLAB как система программирования научно-технических расчетов. — М.: Мир, 2002. — 350 с. 24. Лавров К. Н., Цыплякова Т. П. Финансовая аналитика. MATLAB 6. — М.: Диалог-МИФИ, 2002., - 368 с. 25. Лазарев Ю. Ф. MATLAB 5.x. — Киев: BHV, 2000. - 384 с. 26. Леоненков А. В. Нечеткое моделирование в среде MATLAB и fuzzyTECH. — СПб.: БХВ-Петербург, 2003. — 736 с. 27. Мартынов Н. Н. Введение в MATLAB 6.x. — М.: КУДИЦ-ОБРАЗ, 2002. - 352 с. 28. Мартынов Н. Н., Иванов А. П. MATLAB 5.x. Вычисления, визуализация, программирование. — М.: КУДИЦ-ОБРАЗ, 2000. — 332 с. 29. Мартынов Н. Н., Иванов А. П. MATLAB 5.x. Пособие по программированию в системе MATLAB. - М.: Изд. МГУ, 2000. — 336 с. 30. Медведев В. С, Потемкин В. Г. Control System Toolbox. MATLAB 5 для студентов. — М.: Диалог-МИФИ, 1997. — 287 с. 31. Медведев В. С, Потемкин В. Г. Нейронные сети. MATLAB 6. — М.: Диалог-МИФИ, 2002. — 496 с.
Литература и интернет-источники 725 32. Мэтьюз Дж. Г., Финк К. Д. Численные методы. Использование MATLAB: Пер. с англ. — М.: Изд. дом "Вильяме", 2001. — 713 с. 33. Новгородцев А. Расчет электрических цепей в MATLAB. — СПб.: Питер, 2004. - 250 с. 34. Потемкин В. Г. Система инженерных и научных расчетов MATLAB 5.x: В 2-х кн. - М.: Диалог-МИФИ, 1999. - Кн. 1. - 366 с. 35. Потемкин В. Г. Система инженерных и научных расчетов MATLAB 5.x: В 2-х кн. — М.: Диалог-МИФИ, 1999. - Кн. 2. - 304 с. 36. Потемкин В. Г. MATLAB 5 для студентов / Новая редакция. 2-е изд., испр. и доп. — М.: Диалог-МИФИ, 1999. — 447 с. 37. Потемкин В. Г. MATLAB 6: Среда проектирования инженерных приложений. — М.: Диалог-МИФИ, 2003. — 448 с. 38. Потемкин В. Г. Введение в MATLAB. - М.: Диалог-МИФИ, 2000. — 350 с. 39. Потемкин В. Г. Вычисления в среде MATLAB. — М.: Диалог-МИФИ, 2004. - 720 с. 40. Потемкин В. Г. Инструментальные средства MATLAB 5.x. — М.: Диалог-МИФИ, 2001. - 324 с. 41. Потемкин В. Г. Система MATLAB: Справочное пособие. — М.: Диалог- МИФИ, 1997. - 350 с. 42. Рудаков П. И., Сафонов В. И. Обработка сигналов и изображений. MATLAB 5.x. — М.: Диалог-МИФИ, 2000. — 416 с. 43. Семененко Н. Г. Введение в математическое моделирование. Maple, Mathematica, MATLAB. - М.: СОЛОН, 2002. - 112 с. 44. Чен К., Джиблин П., Ирвинг A. MATLAB в математических исследованиях: Пер. с англ. — М.: Мир, 2001. — 346 с. Методы вычислений 45. Абрамов Л. М., Капустин В. Ф. Математическое программирование. — Л.: Изд. ЛГУ, 1976. - 183 с. 46. Бахвалов Н. С. Численные методы. — М.: Наука, 1973. — 631 с. 47. Беклемишев Д. В. Дополнительные главы линейной алгебры. — М.: Наука, 1983. — 335 с. 48. Березин И. С, Жилков Н. П. Методы вычислений: В 2-х т. — М.: Изд. физ.-мат. литературы, 1959. — Т. 1. — 464 с. 49. Березин И. С, Жидков Н. П. Методы вычислений: В 2-х т. — М.: Изд. физ.-мат. литературы, 1959. — Т. 2. — 620 с.
726 Литература и интернет-источники 50. Гасс С. Линейное программирование (методы и приложения). — М.: Гос. изд-во физико-математической литературы, 1961. — 303 с. 51. Гилл Ф., Мюррей У., Райт М. Практическая оптимизация.— М.: Мир. 1985. — 509 с. 52. Гэри М., Джонсон Д. Вычислительные машины и труднорешаемые задачи: Пер. с англ. — М.: Мир, 1982. — 416 с. 53. Деккер К., Вервер Я. Устойчивость методов Рунге—Кутты для жестких нелинейных дифференциальных уравнений: Пер. с англ. — М.: Мир, 1988. - 332 с. 54. Демидович Б. П., Марон И. А. Основы вычислительной математики. — М.: Изд. физ.-мат. литературы, 1960. — 659 с. 55. Демидович Б. П., Марон И. А., Шувалова Э. 3. Численные методы анализа. — М.: Изд. физ.-мат. литературы, 1962. — 307 с. 56. Завьялов Ю. С, Квасов Б. И., Мирошниченко В. Л. Методы сплайн- функций. — М.: Наука, 1980. — 352 с. 57. Икрамов X. Д. Численное решение матричных уравнений. — М.: Наука, 1984. - 190 с. 58. Кнут Д. Искусство программирования для ЭВМ: В 2-х т. / Получисленные алгоритмы. — М.: Мир, 1977. — Т. 2. — 724 с. 59. Копченова Н. В., Марон И. А. Вычислительная математика в примерах и задачах. — М.: Наука, 1972. — 367 с. 60- Кронрод А. С. Узлы и веса квадратурных формул. Шестнадцатизначные таблицы. — М.: Наука, 1964. — 143 с. 61. Михлин С. Г., Смолицкий X. Л. Приближенные методы решения дифференциальных и интегральных уравнений (Справочная математическая библиотека). — М.: Наука, 1965. — 383 с. 62. Ракитский Ю. В., Устинов С. М., Черноруикий И. Г. Численные методы решения жестких систем. — М.: Наука, 1979. — 208 с. 63. Соболь И. М. Численные методы Монте-Карло. — М.: Наука, 1973. — 311 с. 64. Справочник программиста. — Л.: Изд. судостр. промышленности, 1983.— Т. 1. —628 с. 65. Стренг Г. Линейная алгебра и се применения: Пер. с англ. — М.: Мир, 1980. — 454 с. 66. Форсайт Дж., Молер К. Численное решение систем линейных алгебраических уравнений: Пер. с англ. — М.: Мир, 1969. — 167 с.
Литератора и интернет-источники 727 67. Форсайт Дж., Малькольм М., Моулер К. Машинные методы математических вычислений: Пер. с англ. — М.: Мир, 1980. — 279 с. 68. Химмельблау Д. Прикладное нелинейное программирование: Пер. с англ. — М.: Мир, 1975. — 534 с. Интернет В январе 2004 г. на сайте фирмы MathWorks (http://www.mathworks.com/ moler) появилась прекрасная книга се научного руководителя — "Numerical Computing with MATLAB" в формате PDF. Вы можете скачать книгу полностью или отдельные главы с указанного сайта. Ниже приводятся названия глав и размеры соответствующих файлов. Номер Название главы главы Файл Размер файла, байт Предисловие (Preface) 1 Введение (Introduction) 2 Линейные уравнения (Linear equations) 3 Интерполяций (Interpolation) 4 Решение уравнений (Zero finding) 5 Метод наименьших квадратов (Least squares) 6 Вычисление интегралов (Quadrature) 7 Обыкновенные дифференциальные уравнения (Ordinary differential equations) 8 Случайные числа (Random numbers) 9 Анализ Фурье (Fourier analysis) 10 Собственные вектора и собственные значения (Eigenvalues and singular values) 11 Уравнения в частных производных (Partial differential equations) preface.pdf intro.pdf lu.pdf interp.pdf zeros.pdf leastsquares pdf quad.pdf odes.pdf random.pdf fourier.pdf eigs.pdf 95 090 635 159 390 467 228 895 211 420 220 873 221 404 561 005 159 831 414 646 681 055 pdes.pdf 420 288
Предметный указатель Ambient light 426 Anonymous function 136 Array Editor 14, 119 В Bookmark 153 Breakpoint 150 Camera position 437 Cell 104 Code Composer Studio 10 . Code Division Multiple Access (CDMA) 8 D Diffuse reflection 425 Digital Signal Processing (DSP) 11 E Esc-1 юслежшател ьмость 233 G General Aiitoiegressive Conditional Heteroscedasticity (GARCH) 9 Graphic User Interface (GUI) 258 H Handle 105, 258 I Indent 149 Linear Matrix Inequality (LMI) 10 Logical arrays 106 N Nested function 136 О OLE for Process Control (OPC) 11 Overloaded function 137 Flash 211 Flashing 211 Function handle 105 P-code 126 Pieceweise polinomial form 543 Primary M-File Functions 135 Private function 137
Предметный указатель 729 S Script 123 Shininess coefficient 426 Simulink 7 Single arrays 98 Specular reflection 425 Subfunction 126, 135 T Truncate 210 A Абсолютное зеркальное отражение 425 Ачгоритм: закраски Гуро 436 прямо-двойственный 654 симплексного поиска 614 Аналоговая вычислительная машина (АВМ) 6 Б Банан Розенброка 615 Белый пробел 142, 177, 198, 237 В Вектор: евклидова норма 528 норма 483, 528 ориентированный угол 485 символьный 90 скалярное произведение 481, 483 смешанное произведение 486 собственный 522 Вектор-столбец 33 Вектор-строка 33 Визуализация 273, 421 V View point 437 Virtual Reality Modeling Language (VRML) 12 w Wire frame 432 Workspace 20, 119 Г Градиент функции 562 График 43 в декартовых координатах 43 включение в отчет 76 логарифмический масштаб 52 на заданном интервале 52 д Данные: двоичные 208 текстовые 207 Декартов лист 619 Дескриптор 105 Деструктор 257 Диаграмма: круговая 83 объемная столбиковая 81 плоская столбиковая 77 площадная 86 3 Задача: бинарного линейного программирования 658 (окончание рубрики см. па с. 730)
730 Задача (окончание): квадратичного программирования 653, 667 Кош и для обыкновенного дифференциального уравнения 573 краевая для обыкновенного дифференциально! о уравнения 5S0 линейного программирования 653 математического программирования 653 Закладка 153 Закон Ламберта 426 Знак переноса строки 19 И Изолиния 442 К Класс 255 Axes 274 Figure 266 Image 298 Line 283 Rectangle 287 Root 260 Text 291 базовый 257 производный 257 Команда: clear 21 help 129 load 21 save 20 who 20 whos 13, 20 Комментарий 129 многострочный 131 Компонент: Button Group 316, 336 Checkbox 316, 336 Edit Text 316, 342 Lislbox3l7, 345 Panel 316, 336 Popup Menu 317 Предметный указатель Push Button 316, 32S • Radiobutton 316, 336 Slider 316, 347 Static Text 316, 341 Toggle Button 316, 335 защищенный 258 личный 258 общедоступный 258 Конкатенация строк 171 вертикальная 173 горизонтальная 171 Константа: cps 30 false 106 pi 30 real max 30 realmin 30 tnie 106 литеральная 226 Конструктор 256 Координаты, однородные 422 Коэффициент резкости бликов 426 Л Лексема 181 Линия уровня 442 м Массив: логический 106 пустой 24 символьный 90 строковый 23 Матрица 479 Адамара491 блочная 100 Вапдермоида 493, 536 Ганкеля 492 Гессе 618 Гильберта 490 единичная 487 индекс 34 ленточная 100 магический квадрат 494
Предметный указатель 731 нулевая 487 обратная 5 JI объединение 36 операции 479 ортогональная 490 Паскаля 491 перестановки 501 покомпонентное умножение 480 преобразование 488 псевдообратная 511 псевдоподобная 503 разложение 494 LU 498 QR500 Жордана 509 полярное 504 сингулярное 503 скелетное 496 треугольное 499 Хессенберга 507 Холецкого 500 Шура 505 Эрмита 495 разреженная 100 ранг 481 символьная 90 собственные числа 495 Теплица 492 унитарная 490 Фробениуса 523 характеристический полипом 522 хранение в оперативной памяти 36 число обусловленности 52S Матрицы: кососимметричные 490 косоэрмитовые 490 самосопряженные 490 симметричные 490 эрмитовы 490 Метод 255 Адамса 574 активного набора 667 Гаусса 527 Гаусса—Ньютона 600, 624 Грама—Шмидта 500 деления пополам 595 дихотомии 595 доверительного интернала 618 Куртиса и Хиршфельдера 574 Левенберга—Марквардта 600, 624 Монте-Карло 675 наименьших квадратов 515 Ньютона 618 с доверительным интервалом 667 обратной квадратичной интерполяции 595 Розенброка 573 Рунге—Кутты 574 секуших 595 сопряженных градиентов 667 Минимизация: безусловная 614, 637 условная 614, 637 Модуль полинома 608 н Начало текущей строки 18 Номер файла 209 О Объект 255 Image 460 Light 440 Patch 448 Surface 427 Окно диалоговое 393 выбора: из списка 399 имени файла для записи 412 имени файла для чтения 409 параметров страницы 405 параметров шрифта 415 цвета 413 для ввода строк 397 запроса 408 настройки параметров страницы 403 общего назначения 394 параметров печати 406 с полосой прогресса 417 с сообщением 402 с сообщением об ошибке 395 со справочной информацией 396
732 Предметный указатель Оператор: break 128 end 124 function ч125 global 125 return 129 switch 128 try 128 Лапласа 563 присваивания 128 условный 128 цикла: for 128 while 128 Операция: and 97 cmp 97 or 97 set 97 xor97 арифметическая 37 специальная 37 сравнения 175 Отступ 149 Ошибка п файловой операции 23S п Первичные т-файлы 135 Переменная 20 глобальная: nargin 138, 142 nargoi.it 142 локальная 125 правила именования 20 удаление 21 Подфункция 126, 135 Позиция камеры 437 Поиск: фрагментов текста 200 шаблон 198 Полином 465 интерполяционный 535 Полное диффузное рассеяние 425 Преобразование аффинное 421 Приведение типов 38 Приведенный индекс 23 Приложение: консольное 315 окопное 315 Присваивание множественное 132 Пробел литеральный 197 Проблема собственных значений 522 Проволочный каркас поверхности 432 Программа: explore 108 lint 158 M-Lint 158 Profiler 160 Производная функции 560 Процедура: feval 105 pcodc 126 Псевдокод 126 Р Рабочее пространство 20, 119 Растеризация 423 Регулярные выражения 198 Редактор массивов 14, 119 Рендеринг 273, 421 С Свойство 257 Сингулярное число 503 Система: квадратная крамеровская 512 крамеровская 536 неопределенная 512 совместная 515 Скрипт 123 Случайная траектория 687 Спецификаторы формата 194 Сплайн 539 Ссылка 259 Сценарий 123 т Тип данных 89 char 90 double 25
Предметный указатель 733 functionjiandle 105 logical 106 single 98 запись 101 структура 101 Точка зрения 437 Точка прерывания 150 Триангуляция Делоне 555 Узел 535 Указатель 259 на функцию 105 Уравнение: Вейссинджера 589 дифференциальное 572 матричное 606 Пуассона 520 Усечение 210 Ф Файл: двоичный 213 запись 220 чтение 214 закрытие 212 контроль конца данных 212 открытие 209 текстовый 223 создание 250 чтение 224, 234, 239 Фоновая подсветка 426 Формула: Гаусса 571 Симпсона 566 Фонга 426 Функция 125 abs 32 alpha 462 and 39 angle 32 area 77, 86 atan2 486 axes 326 axis 281 bar 77 ЬагЗ 77 bar3h 77 barn 77 base2dec 190 bin2dec 190 bintprog 659 bitand 97 bitemp 97 bitget 97 bitor 97 bitset 97 bitshift 97 bitxor 97 blanks 170 blkdiag 36 bvp4c 581 bvpinit 581, 585 camlight 441 ceil 41, 231 char 166 chol 500 clabel 442, 444 colormap 77, 306 compan 523 complex 32 cond 52S conj 32 contour 442 contotir3 442, 447 contourc 442, 446 contourf 442, 444 conv 468 cos 39 cross 484 csaps 545 cumtrapz 566 dbclear 155, 156 dbcont 155 dbdown 155, 158 dbquit 155, 158 dbstack 155 dbstatus 155, 156 dbstep 155, 157 (продолжение рубрики см. на с. 734)
734 Предметный указатель Функция (продолжение): dbstop 155, 156 dblype 155 dbup 155, 158 deblank 170 dec2base 190 dec2bin 188 dec2licx 189 decic 589, 590 deconv 468 del2 563 delaunay 555 dialog 394 difT 474, 559 disp 134 dlmread 251 dlnnvriie 250 dot 482 eig 524 error 134, 138 errordlg 395 eval 144 expand 474 expml 42 eye 35, 95, 530 factor 477 false 106 fclosc 212 feof212 ferror 238 feval 144. 145 fgcll 224 fgets 224 fieldnames 102 figure 266, 326 findull 313 findobj 313 findstr 178 fix 41, 231 floor 41, 231 f'miiibud 611 fmincon 638 fniinimax 629, ¢46, 647 fminsearcli 614 fminunc 618 fnder 544 fnint 544 fnval 544 fopen 209, 412 fplot 52. fprintr225 fread 214 frewind 213 fscanf 234 fseek 213 fsolve 599 ftell 213 fwrite 220 fzero 595 gallery 677 gca 259 gcbo 331 gcd 41 gcf 55, 259 gco 259 get 259 gelfield 104 gradient 563 grid on 47 griddata 557 guidata 386 guihandles 385 hadamard 491 liankcl 493 helpdlg 396 hess 507 Iiex2dec 190 hex2iuim 191 hilb 490 hinges 623 hold on 45 imag 32 imread 305, 335 imwrite 312 input 133 inpiitdlg 397 hit 475 int2str 183, interpl 540 interp2 554 intmax 94 intmin 94 185
Предметный указатель 735 intwarning 94 inv 511, 533 invhilb 490 isa 113 iscell 116 iscellstr 116 ischar 115 isempty 116 isfinite 117 isinf 117 isletter 106, 117, 177 islogical 115 isnan 117 isnumeric 115 isprime 106, 118 isreal 114 issorted 118 isspace 106, 177 issparse 116 isstruct 116 Jordan 509 Icm 41 legend 47 length 91, 170 light 440 lightangle 440 line 283 linear 554 linprog 653 listdlg 399 log 569 loglp 42 loglog. 52 lower 183 Isqnonlin 624, 646 In 498 magic 494 mat2str 191 mean 565 mesh 429, 432 meshc 432 meshgrid 428, 553 meshz 432 mod 41 msgbox 402 nargchk 138 nargoutclik 138 nchoosek 42 ndims 91 nextpow2 42 norm 528 not 39 null 514 iuim2str 183 ode 113 575 odel5i 588 ode 15s 575 ode23 575 ode23s 575 ode23t 575 ode23lb 575 ode45 575 odesel 577 ones 34. 95, 530 opti nisei 649, 659 or 39 pagedlg 403 pagesctiipdlg 403, 405 pascal 491 patch 448 pchip 540 peaks 399 perms 42 pie 77, 83 pie3 77, S3 pinv512, 517 plot 43, 270 plolyy 48 poly 471, 523 poly2sym 465 polyder 469 polyf]t 537 polyint 470 polyline 158 polysum 467 polyval 322, 466, 537 polyvalm 467 pow2 42 ppval 540, 544 primes 42 prinldlg 406 putfield 104 qr500 quad 566 quad] 571 (окончание рубрики см. на с. 736)
736 Предметный указатель Функция (окончание): quadprog 667 quadstep 566 questdlg 408 rand 35, 676 randn 35, 677 randperm 677 rank 481 real 32 reallog 42 real max 100 realmin 100 realsqrt 42 rectangle 287 regexp 200 regexpi 200 regexprep 200, .203 rem 41 repmat 104, 171 reshape 519 residue 471 mifield 104 roots 322, 470, 523 - round 231 rref 525 rsOcsf 507 schur 506 semilogx 52 semilogy 52 set 259, 322, 326, 348 sign 42 simplify 473 sin 39 size 91 solve 476 sphere 439 spline 540 sprintr 28, 135, 192, 238 sqrt 39 sscanf 196, 238 str2double 186 str2mat 191 str2num 186, 398 strcat 171 stremp 175 strempi 175, 183 strfind 178 slrjust 170 strmatch 179 strnemp 175 strnempi 175 strrep 180 strtok 142, 181 struct 102 strvcat 173 subplot 49 subs 471 sum 482, 532 surf 429, 436 surfc 436 sym 466 sym2poly 465 text 291 textread 239 title 47 toeplitz 492 trace 533 trapz 564 trimesh 557 true 106 uiconextmenii 350 uicontrol 321 uigetfile 409 uimenii 350 uiputfile 412 uisetcolor 413 uisetfont 415 upper 183 vander 493, 536 view 438 waitbar 417 warndlg 416 warning 134 xlabel 47 xor 39, 127 ylabel 47 zeros 34, 95, 530 анонимная 136
Предметный указатель 737 аргумент, заданный вектором 36 вложенная 136 гармоническая 686 перегружаемая 137 Розенброка 625 унимодальная 611 частная 137 ц Цифровая вычислительная машина (ЦВМ) 6 Число: вещественное 25 комплексное 25 собственное 522 формат вывода 25 целое 25 Я Ячейка 103, 104
как повысить отдачу от вложений в инмо»ма ионн ю инм »acTi кт • компании? обучить специалистов в учебном ц е нт ре s о f 11 i п е *! Даже грамотный специалист, занятый текущей работой, не в состоянии самостоятельно повышать свою квалификацию. Для этого у него нет ни времени, ни методических материалов. Только авторизованное обучение под руководством опытного инструктора позволяет эффективно на 100% использовать все возможности как ГГ-инфраструктуры, так и персонала компании. непрерывное обучение.'Информационные.- технология быстро меняются- Также быстро устаревают линия сотрудников, Мм предлшуем экономичный и э<|кректши-1ЫП способ непрерывного ОбуЧСНИЯ. Мы (Тутояы разработать кпртшрцтицнук! программу обучении слсциальнс! длн сотрудников Нашей компании. Широкий выбор курсов длн npot|K:i4pin>Hjj|u]i ihi(vi:il-ih IT, которые хотят понмеить сноп уровень. Большое пншшпк: уделяется гиццнк'ИМ гохлроеиия пршильцпЛ Л'-нпфркетрукгурЫ современной кпчлапин — вопросам бсэипаеншти, защиты длшых реэсрнниму копированию, адмтшетрнровлнию сети и др. Авторизованное обучение. SofiLinc-" Нплистгл апторплопанимм учебным центром кимпаннп Microsoft, Symantec, f-lirix. VT.RJ ГА.Ч н др. Высокое качество обучения. Обучение недугсертифицированные преподанзтелн поофициальным методическим материалам. Высокое качество обучения пидтверядастси откликами крупнейших компаииП, входящих в ТОТ! lOOpocciifhsonj рынки. Корпоративные программы обучения. sonLinc* ориентируется на лолшеречнкс отношении с корпорз- '111ННМ.ЧИ КПИСН'ш'мИ МЫ ripCA'iarJL'M рЭЯрЯбглку ItLTipcpiJHIIOM ПРОГРАММЫ ОСуЧСИИН CO'ipy/UillKUU, КОТО- р:1я попнолит --экономить ресурсы, Т1ыдс-!ясмые 1м обучение. Обратитесь к консультантам учебного центра Анне Дмитраковой или Нине Доминго по тел.: +7(055)231-39-39 и закажите бесплэтный каталог учебных курсов, sortlne программное обеспечение — лицензирование, обучение, консалтинг ^-'7 ( О 9 5 ) 2 3 1-3 9 -- 3 9 WWW.Softline.ru
www.bhv.ru Иглин С. Математические расчеты на базе MATLAB. (+CD-ROM) Математические расчеты ««6« MATLAB Магазин "Новая техническая книга" СПб., Измайловским пр., д. 29, тел. (812) 251-41-10 Отдел оптовых поставок e-mail: opt@bhv.spb.su В учебном пособии рассмотрены отдельные математические курсы: вариационное исчисление, математическая статистика, теория графов, соответствующие государственному образовательному стандарту общепрофессиональной дисциплины «Математика». Изучение материала книги ориентировано на активное применение MATLAB и других математических пакетов, в том числе разработанного автором Graph Theory Toolbox, размещенного на сайте компании Math- works — производителя MATLAB. Наличие в каждой главе теоретической части, вопросов для самопроверки, примеров решения задач и вариантов домашних заданий позволит студенту, работая в интерактивном режиме за компьютером, пе только изучать математику, но и осваивать работу с современным математическим пакетом. Преподавателям книга будет полезна при проведении лабораторных и практических работ в компьютерном классе, без которых сегодня невозможно представить изучение математики и различных ее спецкурсов. Книга рассчитана на студентов всех форм обучения, аспирантов и преподавателей технических, компьютерных и экономических направлений. - H..IIH щц» ПМПДа. Ont«Hte учевнов посходле CD-ROM содержит интерактивный Web-документ, позволяющий осуществить прямой доступ к пакету MATLAB и произвести расчеты приведенных в книге задач. Сергей Иглин, кандидат технических наук, доцент кафедры прикладной математики Ниционалы-юго технического университета «Харьковский политехнический институт», член экспертной комиссии при редколлегии журнала «Exponenta Pro. Математика в приложениях», автор более 60 научных и методических работ.
" e * . Ануфриев И., Смирнов А., Смирнова Е. " я" MATLAB 7 www.bhv.ru (+CD-ROM) Магазин "Новая техническая книга" СПб., Измайловский пр., д. 29, тел. (812) 251-41-10 Отдел оптовых поставок e-mail: opt@bhv.spb.su <j*- MATLAB I Вам нужно визуализировать данные несколькими щелчками мыши или быстро написать приложение с графическим интерфейсом и широкими возможностями? Вы хотите использовать современные численные алгоритмы для решения различных задач и избежать скрупулезного программировала-* v"^----^-^---1. ния мелких деталей или желаете овладеть основами про- IMatS '■ 'jfUw'*"*-* граммирования в современном пакете? Вам требуется мощный инструмент для научных исследований и практических разработок или среда для обучения информатике и вычислениям? Тогда эта книга по MATLAB 7 — лля вас. Она адресована читателям различного уровня подготовки, в том числе и не имеющим опыта программирования и работы в пакетах. Значительный объем материала отведен вычислительным задачам: решению уравнений, систем линейных и нелинейных уравнений, интегрированию, аппроксимации функций, решению систем обыкновенных дифференциальных уравнений и уравнений в частных производных, задачам оптимизации и работе с разреженными матрицами. Изложены основы программирования на встроенном языке и принципы эффективного написания приложений в MATLAB, вопросы интеграции с MS Word и MS Excel. Рассмотрена работа с массивами и графикой, описаны возможности расширений Toolbox. Авторы сопроводили изложение примерами и заданиями для самостоятельной работы. Для удобства работы с книгой тексты программ собраны "на прилагаемом компакт-диске. Ануфриев Игорь, к. ф.-м. н., доцент кафедры «Прикладная математика» Санкт- Петербургского государственного политехнического университета, автор книги «Самоучитель MATLAB 5.3/б.х», ряда пособий по информатике и более 20 работ по вычислительной математике. Смирнов Александр, к. ф.-м. н., доцент кафедры «Прикладная математика» Санкт- Петербургского государственного политехнического университета, преподаватель математических и компьютерных дисциплин с более чем 27-летним стажем, автор шести пособий по информатике и более 15 научных работ. Смирнова Елена, к. т. н., доцент кафедры «Прикладная математика* Санкт- Петербургского государственного политехнического университета, преподаватель математических и компьютерных дисциплин с более чем 26-летним стажем, автор четырех пособий по компьютерной тематике и более 16 научных работ.
ШВЕСЬ МИР компьютерных книг Уважаемые господа! Издательство "БХВ-Петербург" приглашает специалистов в области компьютерных систем и информационных технологий для сотрудничества в качестве авторов книг по компьютерной тематике. Если Вы знаете и умеете то, что не знают другие, если у Вас много идей и творческих планов, если Вам не нравится то, что уже написано... напишите книгу вместе с "БХВ-Петербург" Ждем в нашем издательстве как опытных, так и начинающих авторов и надеемся на плодотворную совместную работу. С предложениями обращайтесь к главному редактору Екатерине Кондуковой Тел.:(812)251-4244.591-6243 E-mail: kat@bhv.ru Россия, 199397, Санкт-Петербург, а/я 194, www.bhv.ru
В магазине представлена литература по компьютерным технологиям радиотехнике и электронике физике и математике экономике медицине и др. Низкие цены Прямые поставки от издательств Ежедневное пополнение ассортимента Подарки и скидки покупателям Магазин работает с 10.00 до 20.00 без обеденного перерыва выходной день - воскресенье