Показатель лямбда для эквивалентной функции
Ля́мбда-исчисле́ние (λ-исчисление) — формальная система, разработанная американским математиком Алонзо Чёрчем, для формализации и анализа понятия вычислимости.
λ-исчисление может рассматриваться как семейство прототипных языков программирования. Их основная особенность состоит в том, что они являются языками высших порядков. Тем самым обеспечивается систематический подход к исследованию операторов, аргументами которых могут быть другие операторы, а значением также может быть оператор. Языки в этом семействе являются функциональными, поскольку они основаны на представлении о функции или операторе, включая функциональную аппликацию и функциональную абстракцию. λ-исчисление реализовано Джоном Маккарти в языке Лисп. Вначале реализация идеи λ-исчисления была весьма громоздкой. Но по мере развития Лисп-технологии (прошедшей этап аппаратной реализации в виде Лисп-машины) идеи получили ясную и четкую реализацию.
Содержание
Чистое λ-исчисление
Это простейший из семейства прототипных языков программирования, чистое λ-исчисление, термы которого, называемые также объектами (обами), или λ-термами, построены исключительно из переменных применением аппликации и абстракции. Изначально наличия каких-либо констант не предполагается.
Аппликация и абстракция
В основу λ-исчисления положены две фундаментальные операции:
β-редукция
Поскольку выражение обозначает функцию, ставящую в соответствие каждому значение , то для вычисления выражения
,
в которое входят и аппликация и абстракция, необходимо выполнить подстановку числа 3 в терм вместо переменной . В результате получается . Это соображение в общем виде записывается как
η-преобразование
η-преобразование выражает ту идею, что две функции являются идентичными тогда и только тогда, когда, будучи применённые к любому аргументу, дают одинаковые результаты. η-преобразование переводит друг в друга формулы и (в обратную сторону — только если не имеет свободных вхождений в : иначе свободная переменная после преобразования станет связанной внешней абстракцией).
Каррирование (карринг)
Семантика бестипового λ-исчисления
Тот факт, что термы λ-исчисления действуют как функции, применяемые к термам λ-исчисления (то есть, возможно, к самим себе), приводит к сложностям построения адекватной семантики λ-исчисления. Чтобы придать λ-исчислению какой-либо смысл, необходимо получить множество D, в которое вкладывалось бы его пространство функций D → D. В общем случае такого D не существует по соображениям ограничений на мощности этих двух множеств, D и функций из D в D: второе имеет бо́льшую мощность, чем первое.
Эту трудность в начале 1970-х годов преодолел Дана Скотт, построив понятие области D (изначально на полных решётках [1] , в дальнейшем обобщив до полного частично упорядоченного множества со специальной топологией) и урезав D → D до непрерывных в этой топологии функций [2] . На основе этих построений была создана денотационная семантика языков программирования, в частности, благодаря тому, что с помощью них можно придать точный смысл таким двум важным конструкциям языков программирования, как рекурсия и типы данных.
Связь с рекурсивными функциями
Рекурсия — это определение функции через себя; на первый взгляд, лямбда-исчисление не позволяет этого, но это впечатление обманчиво. Например, рассмотрим рекурсивную функцию, вычисляющую факториал:
f(n) = 1, if n = 0; else n × f(n - 1).
В лямбда-исчислении, функция не может непосредственно ссылаться на себя. Тем не менее, функции может быть передан параметр, связанный с ней. Как правило, этот аргумент стоит на первом месте. Связав его с функцией, мы получаем новую, уже рекурсивную функцию. Для этого, аргумент, ссылающийся на себя (здесь обозначен как r), обязательно должен быть передан в тело функции.
g := λr. λn.(1, if n = 0; else n × (r r (n-1))) f := g g
Это решает специфичную проблему вычисления факториала, но решение в общем виде также возможно. Получив лямбда-терм, представляющий тело рекурсивной функции или цикл, передав себя в качестве первого аргумента, комбинатор неподвижной точки возвратит необходимую рекурсивную функцию или цикл. Функции не нуждаются в явной передаче себя каждый раз. Так как существует несколько определений комбинаторов неподвижной точки. Самый простой из них:
В лямбда-исчислении, Y g — неподвижная точка g; продемонстрируем это:
Теперь, чтобы определить факториал, как рекурсивную функцию, мы можем просто написать g (Y g) n, где n — число, для которого вычисляется факториал. Пусть n = 4, получаем:
Каждое определение рекурсивной функции может быть представлено как неподвижная точка соответствующей функции, следовательно, используя Y, каждое рекурсивное определение может быть выражено как лямбда-выражение. В частности, мы можем определить вычитание, умножение, сравнение натуральных чисел рекурсивно.
В языках программирования
Этот код ищет в массиве строк первый элемент, содержащий подстроку " nut ". Таким образом, он выдает следующий результат:
И пока он работает, его можно улучшить.
Корень проблемы здесь в том, что std::find_if требует, чтобы мы передали ей указатель на функцию. Из-за этого мы вынуждены определять функцию, которая будет использоваться только один раз, ей нужно дать имя и поместить в глобальную область видимости (потому что функции не могут быть вложенными!). К тому же эта функция такая короткая, что легче понять, что она делает, по строкам кода, чем по названию и комментариям.
Лямбды спешат на помощь
Лямбда-выражение (также называемое лямбда (lambda) или замыкание (closure)) позволяет нам определять анонимную функцию внутри другой функции. Вложенность важна, поскольку она позволяет нам избежать загрязнения пространств имен и определять функцию как можно ближе к тому месту, где она используется (обеспечивая дополнительный контекст).
Синтаксис лямбда-выражений – одна из самых странных вещей в C++, и к нему нужно немного привыкнуть. Лямбды имеют вид:
Захват и параметры могут быть пустыми, если они не нужны.
Тип возвращаемого значения является необязательным, и если он опущен, будет использоваться значение auto (т.е. использование вывода типа для определения типа возвращаемого значения). Хотя мы ранее отмечали, что следует избегать вывода типа для типов, возвращаемых функцией, в этом контексте его можно использовать (поскольку эти функции обычно очень тривиальны).
Также обратите внимание, что лямбды не имеют имени, поэтому нам не нужно его указывать.
В качестве отступления.
Это означает, что определение простейшего лямбда-выражения выглядит так:
Давайте перепишем приведенный выше пример с помощью лямбда-выражения:
Это работает так же, как и случай с указателем на функцию, и дает идентичный результат:
Обратите внимание, насколько похоже наше лямбда-выражение на нашу функцию containsNut . У них обоих одинаковые параметры и тела функций. Лямбда не имеет захвата (что такое захват, мы объясним в следующем уроке), потому что он не нужен. И мы в лямбде опустили завершающий тип возвращаемого значения (для краткости), но поскольку operator!= возвращает bool , наша лямбда также вернет bool .
Тип лямбды
В приведенном выше примере мы определили лямбду именно там, где это было необходимо. Такое использование лямбды иногда называют функциональным литералом.
Однако запись лямбды в той же строке, где она используется, иногда может затруднить чтение кода. Подобно тому, как мы можем инициализировать переменную литеральным значением (или указателем на функцию) для использования позже, мы также можем инициализировать лямбда-переменную с помощью определения лямбда-выражения, а затем использовать ее позже. Именованная лямбда вместе с хорошим именем функции может упростить чтение кода.
Например, в следующем фрагменте мы используем std::all_of , чтобы проверить, все ли элементы массива четны:
Мы можем улучшить читаемость следующим образом:
Но какой тип у лямбды isEven ?
Оказывается, лямбды не имеют типа, который мы могли бы использовать явно. Когда мы пишем лямбду, компилятор генерирует только для этой лямбды уникальный тип, который нам не предоставляется.
Для продвинутых читателей
На самом деле лямбды не являются функциями (что является частью того, как они избегают ограничения C++, не поддерживающего вложенные функции). Это особый вид объектов, называемых функторами. Функторы – это объекты, которые содержат перегруженный operator() , который делает их вызываемыми как функции.
Хотя мы не знаем тип лямбды, есть несколько способов сохранить лямбду для использования после определения. Если лямбда имеет пустой список захвата, мы можем использовать обычный указатель на функцию. В следующем уроке мы познакомимся с лямбда-захватами, указатель на функцию в этот момент больше не будет работать. Однако для лямбда-выражений можно использовать std::function , даже если они что-то захватывают.
Единственный способ использовать реальный тип лямбды – использовать auto . У auto также есть преимущество в отсутствии дополнительных затрат по сравнению с std::function .
К сожалению, мы не всегда можем использовать auto . В случаях, когда фактическая лямбда неизвестна (например, потому что мы передаем лямбду в функцию в качестве параметра, и вызывающий определяет, какая лямбда будет передана), мы не можем использовать auto без компромиссов. В таких случаях можно использовать std::function .
Вывод этой программы:
Если бы мы использовали auto для типа fn , вызывающий функцию не знал бы, какие параметры и возвращаемый тип должна иметь fn . Кроме того, функции с параметрами auto нельзя разделить на заголовочный и исходный файл. Мы объясняем причину этого ограничения, когда будем говорить о шаблонах.
Правило
Используйте auto при инициализации переменных лямбда-выражениями, или std::function , если вы не можете инициализировать переменную лямбда-выражением.
Обобщенные лямбда-выражения
По большей части параметры лямбд работают по тем же правилам, что и параметры обычных функций.
Одним примечательным исключением является то, что, начиная с C++14, нам разрешено использовать auto для параметров (примечание: в C++20 обычные функции также смогут использовать auto для параметров). Когда лямбда имеет один или несколько параметров auto , компилятор из вызовов лямбды определит, какие типы параметров необходимы.
Поскольку лямбда-выражения с одним или несколькими параметрами auto потенциально могут работать с широким спектром типов, они называются обобщенными лямбда-выражениями.
Для продвинутых читателей
При использовании в контексте лямбда-выражения auto – это просто сокращение для шаблонного параметра.
Давайте посмотрим на обобщенную лямбду:
В приведенном выше примере мы используем параметры auto для захвата наших строк по константной ссылке. Поскольку все строковые типы разрешают доступ к своим отдельным символам через operator[] , нам не нужно заботиться о том, передает ли пользователь std::string , строку в стиле C или что-то еще. Это позволяет нам написать лямбду, которая могла бы принимать любой из этих типов, а это означает, что если мы изменим тип через несколько месяцев, нам не придется переписывать лямбду.
Однако auto не всегда лучший выбор. Рассмотрим следующий код:
В этом примере использование auto приведет к выводу типа const char* . Со строками в стиле C нелегко работать (если не считать использования operator[] ). В этом случае мы предпочитаем явно определить параметр как std::string_view , что позволяет нам намного проще работать с базовыми данными (например, мы можем запросить у строкового представления его длину, даже если пользователь передал массив в стиле C).
Обобщенные лямбды и статические переменные
Следует знать, что для каждого типа, в который выводится auto , будет сгенерирована уникальная лямбда. В следующем примере показано, как одна обобщенная лямбда превращается в две разные лямбды:
В приведенном выше примере мы определяем лямбду, а затем вызываем ее с двумя разными параметрами (строковый литеральный параметр и целочисленный параметр). Это генерирует две разные версии лямбды (одна со строковым литеральным параметром, а другая с целочисленным параметром).
В большинстве случаев это несущественно. Однако обратите внимание, что если обобщенное лямбда-выражение использует переменные статической продолжительности, эти переменные совместно не используются сгенерированными лямбда-выражениями.
Мы можем видеть это в приведенном выше примере, где каждый тип (строковые литералы и целые числа) имеет свой уникальный счетчик! Хотя мы написали лямбду только один раз, было сгенерировано две лямбды, и каждая имеет свою версию callCount . Чтобы иметь общий счетчик для двух сгенерированных лямбда-выражениях, нам нужно определить глобальную переменную или статическую локальную переменную вне лямбда-выражения. Как вы знаете из предыдущих уроков, как глобальные, так и статические локальные переменные могут вызывать проблемы и затруднять понимание кода. Мы сможем избежать этих переменных после того, как поговорим о лямбда-захватах в следующем уроке.
Вывод возвращаемого типа и завершающие возвращаемые типы
Если используется вывод типа возвращаемого значения, возвращаемый тип лямбды выводится из инструкций return внутри лямбды. В этом случае все инструкции return в лямбда-выражении должны возвращать один и тот же тип (иначе компилятор не будет знать, какой из них предпочесть).
Это приводит к ошибке компиляции, поскольку тип возврата первой инструкции return ( int ) не соответствует типу возврата второй инструкции return ( double ).
В случае, если мы возвращаем разные типы, у нас есть два варианта:
- выполните явное приведение, чтобы все возвращаемые типы совпадали, или
- явно укажите тип возвращаемого значения для лямбда-выражения и позвольте компилятору выполнить неявные преобразования.
Второй вариант – обычно лучший выбор:
Таким образом, если вы когда-нибудь решите изменить тип возвращаемого значения, вам (обычно) нужно будет только изменить тип возвращаемого значения лямбды, и не касаться тела лямбда.
Функциональные объекты стандартной библиотеки
Для распространенных операций (например, сложения, отрицания или сравнения) вам не нужно писать свои собственные лямбды, потому что стандартная библиотека поставляется с множеством базовых вызываемых объектов, которые можно использовать вместо этого. Они определены в заголовке .
Вместо того чтобы преобразовывать нашу функцию greater в лямбду (что немного скрывает ее значение), мы можем вместо этого использовать std::greater :
Заключение
Лямбда-выражения и библиотека алгоритмов могут показаться излишне сложными по сравнению с решением, использующим цикл. Однако эта комбинация может позволить реализовать некоторые очень мощные операции всего в нескольких строках кода и может быть более читабельной, чем написание ваших собственных циклов. Вдобавок ко всему, библиотека алгоритмов обладает мощным и простым в использовании параллелизмом, которого вы не получите с циклами. Обновить исходный код, использующий библиотечные функции, проще, чем обновить код, использующий циклы.
Лямбды – это здорово, но они не заменяют обычные функции во всех случаях. Для нетривиальных и многоразовых случаев предпочитайте использование обычных функций.
Небольшой тест
Вопрос 1
Создайте структуру Student , в которой хранятся имя и баллы учащегося. Создайте массив студентов и используйте std::max_element , чтобы найти студента, набравшего наибольшее количество баллов, затем распечатайте имя этого студента. std::max_element принимает начало и конец списка и функцию, которая принимает 2 параметра и возвращает истину, если первый аргумент меньше второго.
Проверьте код на следующем массиве.
Ваша программа должна напечатать
Вопрос 2
Используйте std::sort и лямбда-выражение в следующем коде, чтобы отсортировать сезоны по возрастанию средней температуры (температура приведена в Кельвинах).
В C++ 11 и более поздних версиях лямбда-выражение, — часто называемое —- — функцией, является удобным способом определения объекта анонимной функции ( —) прямо в расположении, где оно вызывается или передается в качестве аргумента функции. Обычно лямбда-выражения используются для инкапсуляции нескольких строк кода, передаваемых алгоритмам или асинхронным функциям. В этой статье определяются лямбда-выражения и их сравнение с другими методами программирования. Он описывает их преимущества и предоставляет некоторые основные примеры.
Связанные статьи
Части лямбда-выражения
В стандарте ISO C++ демонстрируется простое лямбда-выражение, передаваемое функции std::sort() в качестве третьего аргумента:
На следующем рисунке показана структура лямбда-выражения:
предложение Capture (также известное как оператор лямбда-выражения в спецификации C++).
список параметров Используемых. (Также называется лямбда-объявлением)
изменяемая спецификация Используемых.
Спецификация Exception Используемых.
замыкающий-возвращаемый тип Используемых.
Предложение Capture
Лямбда-выражение может добавлять новые переменные в тексте (в C++ 14), а также получать доступ к переменным из окружающей области или записыватьих. Лямбда-выражение начинается с предложения Capture. Он указывает, какие переменные фиксируются, а также указывает, является ли запись по значению или по ссылке. Доступ к переменным с префиксом амперсанда ( & ) осуществляется по ссылке и к переменным, к которым нет доступа по значению.
Пустое предложение фиксации ( [ ] ) показывает, что тело лямбда-выражения не осуществляет доступ к переменным во внешней области видимости.
Можно использовать режим захвата по умолчанию, чтобы указать, как фиксировать все внешние переменные, упоминаемые в теле лямбда-выражения: означает, что [&] все переменные, на которые вы ссылаетесь, захватываются по ссылке, а [=] значит, они записываются по значению. Можно сначала использовать режим фиксации по умолчанию, а затем применить для определенных переменных другой режим. Например, если тело лямбда-выражения осуществляет доступ к внешней переменной total по ссылке, а к внешней переменной factor по значению, следующие предложения фиксации эквивалентны:
При использовании записи по умолчанию фиксируются только те переменные, которые упоминаются в теле лямбда-выражения.
Если предложение Capture включает запись-Default, то & ни один идентификатор в записи этого предложения записи не может иметь форму &identifier . Аналогично, если предложение Capture включает запись по умолчанию = , то ни один из этих предложений не может иметь форму =identifier . Идентификатор или this не может использоваться в предложении Capture более одного раза. В следующем фрагменте кода показаны некоторые примеры.
Захват, за которым следует многоточие, — это расширение пакета, как показано в следующем примере шаблона Variadic :
Чтобы использовать лямбда-выражения в теле функции члена класса, передайте this указатель в предложение Capture, чтобы предоставить доступ к функциям и членам данных включающего класса.
Visual Studio 2017 версии 15,3 и более поздних версий (доступно в режиме и более поздних версиях): this указатель может быть записан по значению путем указания *this в предложении capture. Захват по значению копирует весь замыкание на каждый узел вызова, где вызывается лямбда-выражение. (Замыканием является объект анонимной функции, инкапсулирующий лямбда-выражение.) Захват по значению полезен, когда лямбда выполняется в параллельных или асинхронных операциях. Это особенно полезно на некоторых аппаратных архитектурах, таких как NUMA.
Пример, демонстрирующий использование лямбда-выражений с функциями членов класса, см. в разделе "пример: использование лямбда-выражения в методе" в примерах лямбда-выражений.
При использовании предложения Capture рекомендуется учитывать такие моменты, особенно при использовании лямбда-выражений с многопоточностью:
Захваты ссылок можно использовать для изменения переменных вне, но захваты значений не могут. ( mutable позволяет изменять копии, но не оригиналы.)
Захват ссылок отражает обновления переменных вне, но не фиксирует значения.
Фиксация ссылки вводит зависимость от времени существования, тогда как фиксация значения не обладает зависимостями от времени существования. Это особенно важно при асинхронном выполнении лямбда-выражения. Если вы захватываете локальную по ссылке в асинхронном лямбда-выражении, это локально может быть легко пропала в момент выполнения лямбда-выражения. Код может вызвать нарушение прав доступа во время выполнения.
Обобщенная фиксация (C++14)
В C++ 14 можно ввести и инициализировать новые переменные в предложении Capture, не требуя, чтобы эти переменные существовали в лямбда-функциях, ’ охватывающих область. Инициализация может быть выражена в качестве любого произвольного выражения. Тип новой переменной определяется типом, который создается выражением. Эта функция позволяет собирать переменные только для перемещения (например, std::unique_ptr ) из окружающей области и использовать их в лямбда-выражении.
Список параметров
Лямбда-выражения могут записывать переменные и принимать входные параметры. Список параметров (лямбда-декларатор в стандартном синтаксисе) является необязательным и в большинстве аспектов напоминает список параметров для функции.
В C++ 14, если тип параметра является универсальным, можно использовать ключевое слово в качестве спецификатора типа. Это ключевое слово указывает компилятору создать оператор вызова функции в качестве шаблона. Каждый экземпляр auto в списке параметров эквивалентен отдельному параметру типа.
Поскольку список параметров является необязательным, можно опустить пустые скобки, если аргументы не передаются в лямбда-выражение и его лямбда-декларатор не содержит спецификацию Exception, завершающего-Return-Typeили .
Изменяемая спецификация
Как правило, оператор вызова функции лямбда-выражения является константой по значению, но использование mutable ключевого слова отменяет это. Он не создает изменяемых элементов данных. mutable Спецификация позволяет тексту лямбда-выражения изменять переменные, захваченные по значению. В некоторых примерах, приведенных далее в этой статье, показано, как использовать mutable .
Спецификация исключений
Можно использовать noexcept спецификацию исключения, чтобы указать, что лямбда-выражение не создает никаких исключений. Как и в случае с обычными функциями, компилятор Microsoft C++ создает предупреждение C4297 , если лямбда-выражение объявляет спецификацию исключения, а тело лямбда-выражения создает исключение, как показано ниже:
Дополнительные сведения см. в разделе спецификации исключений (throw).
Возвращаемый тип
Возвращаемый тип лямбда-выражения выводится автоматически. Не обязательно использовать auto ключевое слово, если не указан auto . Замыкающий возвращаемый тип напоминает часть функции, возвращающей возвращаемый тип, и функцию-член. Однако тип возвращаемого значения следует списку параметров, и необходимо включить ключевое слово -> элемента trailing-return-type перед типом возвращаемого значения.
Можно опустить часть возвращаемого типа лямбда-выражения, если тело лямбды содержит только один оператор return. Или, если выражение не возвращает значение. Если тело лямбда-выражения содержит один оператор return, компилятор выводит тип возвращаемого значения из типа возвращаемого выражения. В противном случае компилятор выводит тип возвращаемого значения как void . Рассмотрим следующие примеры фрагментов кода, иллюстрирующих этот принцип:
Лямбда-выражение может создавать другое лямбда-выражение в качестве своего возвращаемого значения. Дополнительные сведения см. в разделе "лямбда-выражения более высокого порядка" в примерах лямбда-выражений.
Тело лямбды
Тело лямбда-выражения является составным оператором. Он может содержать все, что разрешено в теле обычной функции или функции-члена. Тело обычной функции и лямбда-выражения может осуществлять доступ к следующим типам переменных:
Фиксированные переменные из внешней области видимости (см. выше).
Локально объявленные переменные.
Члены данных класса, объявленные внутри класса и this захваченные.
Любая переменная, имеющая статическую длительность хранения — , например глобальные переменные.
В следующем примере содержится лямбда-выражение, которое явно фиксирует переменную n по значению и неявно фиксирует переменную m по ссылке.
Поскольку переменная n фиксируется по значению, ее значение после вызова лямбда-выражения остается равным 0 . mutable Спецификацию можно n изменить в лямбда-выражении.
Лямбда-выражение может записывать только переменные с автоматическим длительностью хранения. Однако можно использовать переменные со статической длительностью хранения в теле лямбда-выражения. В следующем примере функция generate и лямбда-выражение используются для присвоения значения каждому элементу объекта vector . Лямбда-выражение изменяет статическую переменную для получения значения следующего элемента.
Дополнительные сведения см. в разделе Generate.
В следующем примере кода используется функция из предыдущего примера и добавляется пример лямбда-выражения, использующего алгоритм стандартной библиотеки C++ generate_n . Это лямбда-выражение назначает элемент объекта vector сумме предыдущих двух элементов. mutable Ключевое слово используется, чтобы тело лямбда-выражения может изменить свои копии внешних переменных x и y , которое захватывает лямбда-выражение по значению. Поскольку лямбда-выражение захватывает исходные переменные x и y по значению, их значения остаются равными 1 после выполнения лямбда-выражения.
Дополнительные сведения см. в разделе generate_n.
constexpr лямбда-выражения
Visual Studio 2017 версии 15,3 и более поздних версий (доступно в режиме и более поздних версиях): лямбда-выражение можно объявить как constexpr (или использовать его в константном выражении), если инициализация каждого захваченного или введенного элемента данных разрешена в константном выражении.
Лямбда-выражение неявно, constexpr если его результат удовлетворяет требованиям constexpr функции:
Если лямбда-выражение неявно или неявное constexpr , то преобразование в указатель функции создает constexpr функцию:
Специально для систем Майкрософт
Лямбда-выражения не поддерживаются в следующих управляемых сущностях среды CLR: ref class , ref struct , value class или value struct .
Если вы используете модификатор, зависящий от Майкрософт __declspec , например, его можно вставить в лямбда-выражение сразу после parameter-declaration-clause . Пример:
Чтобы определить, поддерживается ли определенный модификатор лямбда-выражениями, см. статью об модификаторе в разделе модификаторы, относящиеся к Microsoft .
Visual Studio поддерживает стандартную лямбда-функцию c++ 11 и лямбда-выражения без отслеживания состояния. Лямбда без отслеживания состояния преобразуется в указатель функции, который использует произвольное соглашение о вызовах.
Многие задаются вопросом зачем он вообще нужен, и зачастую наслушавшись безграмотных советов доморощенных *чиптюнеров* стремятся его разными способами удалить из системы. Не буду долго лить всякую теоретическую воду напишу кратко:
-для владельца авто он позволяет экономить бензин как гласит запись из каталога бош (см. рис.) при исправном двигателе, системе управления ну и собственно лямбда зонде (далее ЛЗ) это реальная экономия до 15% топлива, нетрудно посчитать это 1,5 л на 10 л!
Рисунок 3. Датчик кислорода в выхлопной трубе
1. Керамическое покрытие
2. Электроды
3. Контакты
4. контакты корпуса
5. Выхлопная труба
6. Керамическая поддерживающая оболочка (пористая)
7. Отработавшие газы
8. Наружный воздух.
Датчик кислорода представляет собой гальваническую ячейку (ячейку Нернста) с твёрдым электролитом. В качестве электролита используется газонепроницаемая керамика из диоксида циркония (ZrO2), стабилизированного оксидом иттрия (YO). C одной стороны (снаружи) он сообщается с выхлопными газами, а с другой (изнутри) — с атмосферой. На внешнюю и внутреннюю сторону керамики нанесены газопроницаемые электроды из тонкого слоя платины.
Платиновый электрод на наружной стороне работает как миниатюрный катализатор, поддерживающий в прилегающем слое поступающих выхлопных газов химические реакции, этот слой в состояние стехиометрического равновесия. Сторона чувствительной керамики, обращенная к отработавшим газам, во избежание ее загрязнения покрыта слоем пористой шпинелевой керамики (Шпинель — минералогическое название тетраоксида диалюминия-магния). Металлическая трубка со щелями предохраняет керамику от ударов и чрезмерных тепловых воздействий. Внутренняя полость сообщается с атмосферой и служит в качестве референсной (опорной) стороны датчика.
Работа датчика основана на принципе ячейки Нернста (гальванической ячейки). Керамический материал пропускает ионы кислорода при температурах от 350oC и выше. Разница в количестве кислорода с разных сторон чувствительной зоны датчика приводит к образованию электрического потенциала (напряжения) между этими двумя поверхностями (внутренней и внешней). Величина напряжения служит показателем того, на сколько количество кислорода на этих двух поверхностях различается. А количество остаточного кислорода в выхлопных газах точно соответствует пропорции между топливом и воздухом, поступающими в двигатель.
Широкополосный λ-датчик кислорода
Рисунок . Конструкция широкополосного датчика кислорода непрерывного действия, установленного в выхлопной трубе.
1. Ячейка Нернста
2. Референсная ячейка
3. Подогреватель
4. Диффузионная щель
5. Насосная ячейка
6. Выхлопная труба
Эта конфигурация отличается от обычного датчика с двумя состояниями постоянным поддержанием стехиометрического соотношением воздух/топливо в диффузионной камере. Электронная схема модуляции напряжения питания поддерживает в измерительной камере состав газов, соответствующий λ=1. Для этого насосная ячейка при работе двигателя на бедной смеси и избытке кислорода в выхлопных газах удаляет кислород из диффузионной щели во внешнюю среду; а при богатой смеси и недостатке кислорода в выхлопных газах перекачивает ионы кислорода из окружающей среды в диффузионную щель. Направление тока для перекачивания кислорода в разные стороны тоже отличается.
Так как насосный ток пропорционален концентрации кислорода — он и является показателем величины λ-фактора отработавших газов.
Таким образом, если обычные датчики используют напряжение на ячейке Нернста для прямого измерения и определения одного из двух состояний (λ>1 или λ
Рисунок . Схема замкнутой петли λ-регулирования качества смеси.
1. Датчик массового расхода воздуха
2. Двигатель
3a. Датчик кислорода 1
3b. Датчик кислорода 2
4. Катализатор
5. Форсунки инжектора
6. Электронный Блок Управления
Vv напряжение управления форсунками
Vs напряжение с датчика
Qe Количество впрыскиваемого топлива
Датчик кислорода передает сигнал (напряжение) электронному блоку управления (ЭБУ) двигателем. Этот сигнал используется системой для обогащения или обеднения смеси в соответствии с величиной напряжения с датчика (см. Рис. 8). Таким образом система обогащает бедную смесь, увеличивая количество впрыскиваемого топлива, и обедняет богатую, уменьшая количество топлива.
Диагностика
Лямбда-зонд сравнивает уровень содержания кислорода в выхлопных газах и в окружающем воздухе и представляет результат этого сравнения в форме аналогового сигнала. Применяются двухуровневые зонды, чувствительный элемент которых выполнен из оксида циркония либо из оксида титана, но на их смену приходят широкополосные лямбда-зонды. При условии сгорания стехиометрической топливо-воздушной смеси, напряжение выходного сигнала лямбда-зонда равно 445…450mV.
Но расстояние от выпускных клапанов газораспределительного механизма двигателя до места расположения датчика и значительное время реакции чувствительного элемента датчика приводят к некоторой инерционности системы, что не позволяет непрерывно поддерживать стехиометрический состав топливо-воздушной смеси. Практически, при работе двигателя на установившемся режиме, состав смеси постоянно отклоняется от стехиометрического в диапазоне ±2…3% с частотой 1…2раза в секунду. Этот процесс чётко прослеживается по осциллограмме напряжения выходного сигнала лямбда-зонда.
осциллограмма напряжения выходного сигнала исправного лямбда-зонда BOSCH.
Двигатель работает на холостом ходу. Частота переключения сигнала составляет ~1,2Hz.
Осциллограмма напряжения выходного сигнала неисправного лямбда-зонда BOSCH.
Осциллограмма напряжения выходного сигнала неисправного лямбда-зонда BOSCH. Двигатель работает на холостом ходу. Переключения выходного сигнала отсутствуют. Напряжение выходного сигнала стареющего лямбда-зонда при работе двигателя на холостом ходу становится почти стабильным, его значение становится близким опорному напряжению 300…600mV.
Уровень содержания кислорода в камере с атмосферным воздухом при этом оказывается значительно выше уровня содержания кислорода в выхлопных газах, вследствие чего зонд генерирует напряжение 1V положительной полярности. В случае разгерметизации лямбда-зонда, в камеру с атмосферным воздухом проникают отработавшие газы с низким содержанием кислорода. На режиме торможения двигателем (закрытая дроссельная заслонка при вращении двигателя с высокой частотой, подача топлива при этом отключена), в выхлопную систему двигателем выбрасывается почти чистый атмосферный воздух. В таком случае, уровень содержания кислорода в выхлопной системе резко возрастает и уровень содержания кислорода в атмосферной камере зонда оказывается значительно ниже уровня содержания кислорода в отработавших газах, вследствие чего зонд генерирует напряжение 1V отрицательной полярности. Блок управления двигателем в таком случае считает лямбда-зонд исправным, так как вскоре после пуска двигателя и прогрева, датчик отклонил опорное напряжение и снизил его до ~0V.
Выходное напряжение зонда напряжением ~0V свидетельствует о близком уровне содержания кислорода в отработавших газах и в разгерметизированой атмосферной камере зонда. На блок управления двигателем поступает сигнал зонда низкого уровня, что является для него свидетельством обеднённой топливовоздушной смеси. Вследствие этого, блок управления двигателем обогащает топливовоздушную смесь. Таким образом, разгерметизация лямбда-зонда приводит к значительному обогащению топливовоздушной смеси. При этом многие системы самодиагностики выявить данную неисправность зонда не способны.
Широкополосный лямбда-зонд Выходной сигнал широкополосного лямбда-зонда в отличие от двухуровневых зондов несёт сведения не только о направлении отклонения состава рабочей смеси от стехиометрического, но и о его численном значении. Анализируя уровень выходного сигнала широкополосного лямбда-зонда, блок управления двигателем рассчитывает численное значение коэффициента отклонения состава рабочей смеси от стехиометрического состава, что, по сути, является коэффициентом лямбда.
Для широкополосных зондов производства BOSCH Выходное напряжение чувствительного элемента зонда (чёрный провод относительно жёлтого провода) изменяется в зависимости от уровня содержания кислорода в отработавших газах и от величины и полярности электрического тока, протекающего по кислородному насосу зонда (красный провод относительно жёлтого). Блок управления двигателем генерирует и подаёт на кислородный насос зонда электрический ток, величина и полярность которого обеспечивает поддержание выходного напряжения чувствительного элемента зонда на заданном уровне (450 mV). Если бы двигатель работал на топливовоздушной смеси стехиометрического состава, то блок управления двигателем установил бы на красном проводе напряжение равное напряжению на жёлтом проводе, и ток протекающий через красный провод и кислородный насос зонда был бы равен нулю.
При работе двигателя на обеднённой смеси, блок управления двигателем на красный провод подаёт положительное напряжение относительно жёлтого провода, и через кислородный насос начинает течь ток положительной полярности. При работе двигателя на обогащенной смеси, блок управления изменяет полярность напряжения на красном проводе относительно жёлтого провода, и направление тока кислородного насоса так же изменяется на отрицательное. Величина тока кислородного насоса устанавливаемая блоком управления двигателем зависит от величины отклонения состава топливовоздушной смеси от стехиометрического состава. В электрическую цепь кислородного насоса включен измерительный резистор, падение напряжения на котором и является мерой уровня содержания кислорода в отработавших газах.
Проблемы
Проблема заключается в следующем, цена на новый ЛЗ сейчас очень высока. На рынках в магазинах сейчас очень часто попадаются бракованные, поддельные ЛЗ, в случае установки его в выпуск, обратно вернуть его уже весьма проблематично.
Из того что испытывалось, нагрев строительным феном ЛЗ до 350 С с подачей опорного напряжения 0,45 в никакой реакции (способ найден в инете!) на ламповом оссцилоскопе с высоким входным сопротивлением.
Но порадовало одно у чуствительного элемента ЛЗ есть емкость где то в районе 50-80 Пикофарад.
Другой более надежный способ рожденный опытом это берем газовый паяльник и нагреваем чуствительный элемент при этом разьем лямды подключен к эбу и смотрим на отклонение напряжения от опорного, в небольших пределах мы увидим отклонение что косвенно потверждает его исправность.
Меня интересуют варианты безустановочной диагностики ЛЗ. Буду рад любым идеям, даже самым бредовым на первый взгляд.
Читайте также: