Mastering Qt 5 学习笔记-Mandelbrot

article/2025/9/15 19:06:55

在这里插入图片描述

是一个 Mandelbrot 分形的多线程计算。 用户将看到分形,并能够在该窗口中平移和缩放。Mandelbrot 分形是一个处理复数 (a + bi) 的数值集,该图像中的每个黑色像素都趋向于发散到一个无限值,,而绿色像素则有界于一个有限值。绿色像素属于 Mandelbrot 集。CPU 架构的浮点数精度限制了缩放。如果继续缩放,则会出现视觉伪像,因为比例因子只能处理 15 到 17 位有效数字。
必须仔细设计应用程序的架构。因为我们在使用线程,所以很容易导致死锁、线程饥饿,甚至更糟的是,冻结 UI。我们真的想最大限度地利用 CPU。为此,我们将在每个内核上执行尽可能多的线程。每个线程将负责在返回结果之前计算 Mandelbrot 集的一部分。

在这里插入图片描述

MandelbrotWidget:这要求显示图片。它处理绘图和用户交互。这个对象存在于 UI 线程中。

MandelbrotCalculator:它处理图片请求并在将其发送回

MandelbrotWidget 之前聚合生成的 JobResults。这个对象存在于它自己的线程中。

Job:这会在将结果传输回 MandelbrotCalculator 之前计算最终图片的一部分.每个作业都存在于自己的线程中。

MandelbrotCalculator 线程将使用 QThreadPool 类在它们自己的线程中分派作业。这将根据您的 CPU 内核完美扩展。

每个Job将计算最终图片的一行,然后通过 JobResult 对象将其发送回 MandelbrotCalculator。

MandelbrotCalculator 线程实际上是计算的协调者。考虑一个用户在计算完成之前放大图片

MandelbrotWidget 将向 MandelbrotCalculator 请求一张新图片,MandelbrotCalculator 又必须在分派新作业之前取消所有当前作业

使用 QRunnable 定义作业类

让我们深入了解项目的核心。为了加速 Mandelbrot 图片生成,我们将整个计算拆分为多个作业。作业是任务的请求。 根据您的 CPU 架构,多个作业将同时执行。Job 类产生一个包含结果值的 JobResult 函数。Job 类为完整图片的一行生成值。 例如,800 x 600 的图像分辨率需要 600 个作业,每个作业生成 800 个值。

JobResult.h

#ifndef JOBRESULT_H
#define JOBRESULT_H#include <QSize>
#include <QVector>
#include <QPointF>struct JobResult
{//输入数据(areaSize,pixelPositionY,...)//作业类生成的Result值JobResult(int valueCount = 1) :areaSize(0, 0),pixelPositionY(0),moveOffset(0, 0),scaleFactor(0.0),values(valueCount){}QSize areaSize;int pixelPositionY;QPointF moveOffset;double scaleFactor;QVector<int> values;
};#endif // JOBRESULT_H

Job.h

#ifndef JOB_H
#define JOB_H#include <QObject>
#include <QRunnable>
#include <QPointF>
#include <QSize>
#include <QAtomicInteger>#include "JobResult.h"class Job : public QObject, public QRunnable
{//这个Job类是一个QRunnable,所以我们可以重写run()来实现Mandelbrot图片算法//Job 也继承自 QObject,让我们可以使用 Qt 的信号/槽特性Q_OBJECT
public:Job(QObject *parent = 0);void run() override;void setPixelPositionY(int value);void setMoveOffset(const QPointF& value);void setScaleFactor(double value);void setAreaSize(const QSize& value);void setIterationMax(int value);signals://当算法结束时,将发出 jobCompleted() 信号//jobResult 参数包含结果值void jobCompleted(JobResult jobResult);public slots://abort() 槽将允许我们停止更新 mIsAbort 标志值的作业void abort();private://mAbort 不是经典的 bool,而是 QAtomicInteger<bool>//这种 Qt 跨平台类型使我们可以不间断地执行原子操作//您可以使用互斥锁或其他同步机制来完成这项工作//但使用原子变量是安全更新和访问来自不同线程的变量的快速方法QAtomicInteger<bool> mAbort;//mPixelPositionY变量是图片高度索引//因为每个Job只为一个图片行生成数据,所以我们需要这些信息int mPixelPositionY;//mMoveOffset变量是Mandelbrot原点偏移量//用户可以平移图片,因此原点不会总是 (0, 0)QPointF mMoveOffset;//mScaleFactor 用户还可以放大图片。double mScaleFactor;//mAreaSize 变量是以像素为单位的最终图片大小QSize mAreaSize;//mIterationMax 变量是允许确定一个像素的 Mandelbrot 结果的迭代次数int mIterationMax;
};#endif // JOB_H

Job.cpp

#include "Job.h"Job::Job(QObject* parent) :QObject(parent),mAbort(false),mPixelPositionY(0),mMoveOffset(0.0, 0.0),mScaleFactor(0.0),mAreaSize(0, 0),mIterationMax(1)
{
}void Job::run()
{//初始化一个 JobResult 变量//区域大小的宽度用于将JobResult::values构造为具有正确初始大小的QVector//其他输入数据从Job 复制到JobResult,让JobResult 的接收者得到带有上下文输入数据的结果JobResult jobResult(mAreaSize.width());jobResult.areaSize = mAreaSize;jobResult.pixelPositionY = mPixelPositionY;jobResult.moveOffset = mMoveOffset;jobResult.scaleFactor = mScaleFactor;double imageHalfWidth = mAreaSize.width() / 2.0;double imageHalfHeight = mAreaSize.height() / 2.0;//for循环在一行上遍历所有x个像素位置for (int imageX = 0; imageX < mAreaSize.width(); ++imageX) {if (mAbort.load()) {return;}int iteration = 0;//像素位置转换为复平面坐标double x0 = (imageX - imageHalfWidth) * mScaleFactor + mMoveOffset.x();double y0 = (mPixelPositionY - imageHalfHeight) * mScaleFactor - mMoveOffset.y();double x = 0.0;double y = 0.0;//如果试验次数超过最大迭代次数do {double nextX = (x * x) - (y * y) + x0;y = 2.0 * x * y + y0;x = nextX;iteration++;} while(iteration < mIterationMax&& (x * x) + (y * y) < 4.0);jobResult.values[imageX] = iteration;}emit jobCompleted(jobResult);
}void Job::setPixelPositionY(int value)
{mPixelPositionY = value;
}void Job::setMoveOffset(const QPointF& value)
{mMoveOffset = value;
}void Job::setScaleFactor(double value)
{mScaleFactor = value;
}void Job::setAreaSize(const QSize& value)
{mAreaSize = value;
}void Job::setIterationMax(int value)
{mIterationMax = value;
}
//此方法执行值 true 的原子写入
//原子机制确保我们可以从多个线程调用 abort() 而不会中断 run() 函数中的 mAbort 读取
void Job::abort()
{mAbort.store(true);
}

在 MandelbrotCalculator 中使用 QThreadPool

MandelbrotCalculator.h

#ifndef MANDELBROTCALCULATOR_H
#define MANDELBROTCALCULATOR_H#include <QObject>
#include <QSize>
#include <QPointF>
#include <QElapsedTimer>
#include <QList>#include "JobResult.h"class Job;class MandelbrotCalculator : public QObject
{Q_OBJECT
public:explicit MandelbrotCalculator(QObject *parent = 0);signals://pictureLinesGenerated():这个信号被定期触发以发送结果void pictureLinesGenerated(QList<JobResult> jobResults);//abortAllJobs():该信号用于中止所有活动作业void abortAllJobs();public slots://generatePicture():调用者使用这个槽来请求一个新的 Mandelbrot 图片//此功能准备并启动作业void generatePicture(QSize areaSize, QPointF moveOffset, double scaleFactor, int iterationMax);//process():这个槽处理作业产生的结果void process(JobResult jobResult);private://createJob():这是一个创建和配置新作业的辅助函数Job* createJob(int pixelPositionY);//clearJobs():此插槽删除排队的作业并中止活动的作业void clearJobs();private:QPointF mMoveOffset;double mScaleFactor;QSize mAreaSize;int mIterationMax;//mReceivedJobResults 变量是接收到的 JobResult 的计数,它是由作业发送的int mReceivedJobResults;//mJobResults 变量是一个包含接收到的 JobResult 的列表QList<JobResult> mJobResults;//mTimer 变量计算为请求的图片运行所有作业所用的时间QElapsedTimer mTimer;
};#endif // MANDELBROTCALCULATOR_H

MandelbrotCalculator.cpp

#include "MandelbrotCalculator.h"
#include <QDebug>
#include <QThreadPool>
#include "Job.h"
const int JOB_RESULT_THRESHOLD = 10;
MandelbrotCalculator::MandelbrotCalculator(QObject *parent): QObject(parent),mMoveOffset(0.0, 0.0),mScaleFactor(0.005),mAreaSize(0, 0),mIterationMax(10),mReceivedJobResults(0),mJobResults(),mTimer()
{
}void MandelbrotCalculator::generatePicture(QSize areaSize, QPointF moveOffset, double scaleFactor, int iterationMax)
{if (areaSize.isEmpty()) {return;}//启动 mTimer来跟踪整个生成时长mTimer.start();//每个新的图片生成将首先通过调用 clearJobs() 取消现有作业clearJobs();mAreaSize = areaSize;mMoveOffset = moveOffset;mScaleFactor = scaleFactor;mIterationMax = iterationMax;for(int pixelPositionY = 0; pixelPositionY < mAreaSize.height(); pixelPositionY++) {//QThreadPool::globalInstance() 是一个静态函数,它根据 CPU 的核心数为我们提供最佳全局线程池//即使我们为所有 Job 类调用 start(),也只有第一个类会立即启动//其他人被添加到等待可用线程的池队列中QThreadPool::globalInstance()->start(createJob(pixelPositionY));}
}
//每次作业完成其任务时都会调用此槽
void MandelbrotCalculator::process(JobResult jobResult)
{//首先要检查的是当前的 JobResult 对于当前的输入数据是否仍然有效//当请求新图片时,我们清除作业队列并中止活动作业if (jobResult.areaSize != mAreaSize ||jobResult.moveOffset != mMoveOffset ||jobResult.scaleFactor != mScaleFactor) {return;}//如果旧的 JobResult 仍然发送到这个 process() 槽//我们可以增加 mReceivedJobResults 计数器并将此 JobResult 附加到我们的成员队列 mJobResultsmReceivedJobResults++;mJobResults.append(jobResult);if (mJobResults.size() >= JOB_RESULT_THRESHOLD || mReceivedJobResults == mAreaSize.height()) {emit pictureLinesGenerated(mJobResults);mJobResults.clear();}if (mReceivedJobResults == mAreaSize.height()) {qDebug() << "Generated in " << mTimer.elapsed() << " ms";}
}Job* MandelbrotCalculator::createJob(int pixelPositionY)
{//作业是在堆上分配的//此操作在 MandelbrotCalculator 线程中需要一些时间//当我们调用 QThreadPool::start() 时,线程池获得了作业的所有权//它会在 Job::run() 结束时被线程池删除Job* job = new Job();job->setPixelPositionY(pixelPositionY);job->setMoveOffset(mMoveOffset);job->setScaleFactor(mScaleFactor);job->setAreaSize(mAreaSize);job->setIterationMax(mIterationMax);//发出 abortAllJobs() 信号将调用所有作业的 abort() 槽connect(this, &MandelbrotCalculator::abortAllJobs,job, &Job::abort);//每次 Job 完成其任务时都会执行我们的 process() 槽connect(job, &Job::jobCompleted,this, &MandelbrotCalculator::process);return job;
}void MandelbrotCalculator::clearJobs()
{mReceivedJobResults = 0;emit abortAllJobs();QThreadPool::globalInstance()->clear();
}

您应该识别一些已知的变量名称,例如 mScaleFactor、mMoveOffset、mAreaSize 或 mIterationMax

#ifndef MANDELBROTWIDGET_H
#define MANDELBROTWIDGET_H#include <memory>#include <QWidget>
#include <QPoint>
#include <QThread>
#include <QList>#include "MandelbrotCalculator.h"class QResizeEvent;class MandelbrotWidget : public QWidget
{Q_OBJECTpublic:explicit MandelbrotWidget(QWidget *parent = 0);~MandelbrotWidget();public slots://processJobResults() 函数将处理由 MandelbrotCalculator 调度的 JobResult 列表void processJobResults(QList<JobResult> jobResults);signals://每次用户更改输入数据(偏移、比例或区域大小)时都会发出 requestPicture() 信号void requestPicture(QSize areaSize, QPointF moveOffset, double scaleFactor, int iterationMax);protected://PaintEvent() 函数使用当前 mImage 绘制widgetvoid paintEvent(QPaintEvent* event) override;//当用户调整窗口大小时,resizeEvent() 函数会调整 Mandelbrot 区域的大小void resizeEvent(QResizeEvent* event) override;//wheelEvent() 函数处理用户鼠标滚轮事件以应用比例因子void wheelEvent(QWheelEvent* event) override;//mousePressEvent() 函数和 mouseMoveEvent() 检索用户鼠标事件以移动 Mandelbrot 图片void mousePressEvent(QMouseEvent* event) override;void mouseMoveEvent(QMouseEvent* event) override;private://generateColorFromIteration() 是一个辅助函数,用于对 Mandelbrot 图片进行着色。 按像素的迭代值转换为颜色值QRgb generateColorFromIteration(int iteration);private://mMandelbrotCalculator 变量是我们的多线程作业管理器,widget将向它发出请求并等待结果MandelbrotCalculator mMandelbrotCalculator;//mThreadCalculator 变量允许 Mandelbrot 计算器在它自己的线程中运行QThread mThreadCalculator;double mScaleFactor;//widget使用mLastMouseMovePosition变量来处理平移功能的用户事件QPoint mLastMouseMovePosition;QPointF mMoveOffset;QSize mAreaSize;int mIterationMax;//mImage 变量是widget显示的当前图片。 它是一个unique_ptr指针,因此MandelbrotWidget是mImage的所有者std::unique_ptr<QImage> mImage;
};#endif // MANDELBROTWIDGET_H

MandelbrotWidget.cpp

#include "MandelbrotWidget.h"#include <QResizeEvent>
#include <QImage>
#include <QPainter>
#include <QtMath>const int ITERATION_MAX = 4000;
const double DEFAULT_SCALE = 0.005;
const double DEFAULT_OFFSET_X = -0.74364390249094747;
const double DEFAULT_OFFSET_Y = 0.13182589977450967;MandelbrotWidget::MandelbrotWidget(QWidget *parent) :QWidget(parent),mMandelbrotCalculator(),mThreadCalculator(this),mScaleFactor(DEFAULT_SCALE),mLastMouseMovePosition(),mMoveOffset(DEFAULT_OFFSET_X, DEFAULT_OFFSET_Y),mAreaSize(),mIterationMax(ITERATION_MAX)
{mMandelbrotCalculator.moveToThread(&mThreadCalculator);connect(this, &MandelbrotWidget::requestPicture,&mMandelbrotCalculator, &MandelbrotCalculator::generatePicture);connect(&mMandelbrotCalculator, &MandelbrotCalculator::pictureLinesGenerated,this, &MandelbrotWidget::processJobResults);mThreadCalculator.start();
}MandelbrotWidget::~MandelbrotWidget()
{ mThreadCalculator.quit();mThreadCalculator.wait(1000);if (!mThreadCalculator.isFinished()) {mThreadCalculator.terminate();}
}void MandelbrotWidget::processJobResults(QList<JobResult> jobResults)
{int yMin = height();int yMax = 0;for(JobResult& jobResult : jobResults) {if (mImage->size() != jobResult.areaSize) {continue;}int y = jobResult.pixelPositionY;QRgb* scanLine = reinterpret_cast<QRgb*>(mImage->scanLine(y));for (int x = 0; x < mAreaSize.width(); ++x) {scanLine[x] = generateColorFromIteration(jobResult.values[x]);}if (y < yMin) {yMin = y;}if (y > yMax) {yMax = y;}}repaint(0, yMin,width(), yMax);
}void MandelbrotWidget::resizeEvent(QResizeEvent* event)
{mAreaSize = event->size();mImage = std::make_unique<QImage>(mAreaSize, QImage::Format_RGB32);mImage->fill(Qt::black);emit requestPicture(mAreaSize, mMoveOffset, mScaleFactor, mIterationMax);
}void MandelbrotWidget::wheelEvent(QWheelEvent* event)
{int delta = event->delta();mScaleFactor *= qPow(0.75, delta / 120.0);emit requestPicture(mAreaSize, mMoveOffset, mScaleFactor, mIterationMax);
}void MandelbrotWidget::mousePressEvent(QMouseEvent* event)
{if (event->buttons() & Qt::LeftButton) {mLastMouseMovePosition = event->pos();}
}void MandelbrotWidget::mouseMoveEvent(QMouseEvent* event)
{if (event->buttons() & Qt::LeftButton) {QPointF offset = mLastMouseMovePosition - event->pos();mLastMouseMovePosition = event->pos();offset.setY(-offset.y());mMoveOffset += offset * mScaleFactor;emit requestPicture(mAreaSize, mMoveOffset, mScaleFactor, mIterationMax);}
}void MandelbrotWidget::paintEvent(QPaintEvent* event)
{QPainter painter(this);painter.save();QRect imageRect = event->region().boundingRect();painter.drawImage(imageRect, *mImage, imageRect);painter.setPen(Qt::white);painter.drawText(10, 20, QString("Size: %1 x %2").arg(mImage->width()).arg(mImage->height()));painter.drawText(10, 35, QString("Offset: %1 x %2").arg(mMoveOffset.x()).arg(mMoveOffset.y()));painter.drawText(10, 50, QString("Scale: %1").arg(mScaleFactor));painter.drawText(10, 65, QString("Max iteration: %1").arg(ITERATION_MAX));painter.restore();
}QRgb MandelbrotWidget::generateColorFromIteration(int iteration)
{if (iteration == mIterationMax) {return qRgb(50, 50, 255);}return qRgb(0, 0, (255.0 * iteration / mIterationMax));
}

http://chatgpt.dhexx.cn/article/vUc8yaIi.shtml

相关文章

Mandelbrot集合及其渲染

什么是Mandelbrot集合&#xff1f; Mandelbrot集合是在复数平面上组成分形的点的集合&#xff0c;它正是以数学家Mandelbrot命名。 Mandelbrot集合可以用复二次多项式\[ f_c(z)z^2c \] 来定义 其中c是一个复数。对于每一个c&#xff0c;从\(z 0\),开始对\(f_c(z)\)进行迭代。 …

分形之父 Mandelbrot

著名数学家&#xff0c;被誉为分形之父的Mandelbrot先生&#xff0c;美国时间10月15日在马萨诸塞州剑桥辞世&#xff0c;享年85岁。他用“美丽”改变了我们的世界观&#xff0c;他被认为是20世纪后半叶少有的影响深远而且广泛的科学伟人之一&#xff0c;1993年他获得沃尔夫物理…

Ettercap系列 II:基于命令行界面(结合driftnet截获目标机器正在浏览的图片)

相信跟着这个系列走&#xff0c;一直看到这篇文章的读者已经了解了基于图形化Ettercap的操作&#xff0c;并对Arp欺骗和Ettercap相关的术语有所了解。本篇就如何在命令行界面下操作ettercap&#xff0c;以实现与图形化界面相同的效果展开讨论。可能你会不解&#xff1a;既然我已…

无线局域网的嗅探攻击和防御——ettercap+driftnet

&#xfeff;&#xfeff; 无线局域网的嗅探攻击和防御 -----ettercapdriftnet 1 实验要求和目的 ●了解局域网转发数据的规则与协议 ●了解抓包软件的原理与操作流程 ●对网络中数据传输的协议有更深层次的认识 2 实验原理和背景知识 2.1 抓包软件与分析软件 本次嗅探试验所…

python实现图片嗅探工具——自编driftnet

python实现图片嗅探工具——自编driftnet 前言一、数据包嗅探二、图片捕获三、图片显示及主函数写在最后 前言 想必尝试过中间人攻击&#xff08;MITM)的小伙伴&#xff0c;大概率是知道driftnet的。这是一款简单使用的图片捕获工具&#xff0c;可以很方便的从网络数据包中抓取…

kali中 arpspoof、driftnet、流量转发的图片抓取

1、开启内核转发模式&#xff08;echo 1为转发 echo 0为拦截&#xff09; echo 1 /proc/sys/net/ipv4/ip_forward 配置完成使用命令查看cat /proc/sys/net/ipv4/ip_forward 2、使用 Arpspoof 开始攻击 命令:Arpspoof -i (自己网卡) -t 目标IP 网关 3、打开另一个终端 查看dri…

ARP欺骗攻击(流量图片)——dsniff与driftnet使用

ARP欺骗攻击&#xff08;流量&图片&#xff09; 原理&#xff1a; 首先我们![请添加图片描述](https://img-blog.csdnimg.cn/7de7923387224bcda1ea4be958032ae9.png 要明白何为ARP&#xff08;地址解析协议&#xff09;&#xff1a;是根据 IP地址 获取 物理地址 的一个 TC…

NO.26——利用ettercap和driftnet截获数据流里的图片

原理 Ettercap最初设计为交换网上的sniffer&#xff0c;但是随着发展&#xff0c;它获得了越来越多的功能&#xff0c;成为一款有效的、灵活的中介攻击工具。它支持主动及被动的协议解析并包含了许多网络和主机特性&#xff08;如OS指纹等&#xff09;分析。 Ettercap…

linux嗅探器抓包,Kali Linux 嗅探/欺骗工具 driftnet 教程

日期:2018年01月11日 观看: 13,491 C 次 Driftnet是一个监听网络流量并从它观察到的TCP流中提取图像的程序。有趣的是看到很多网络流量的主机上运行。在实验性增强中,driftnet现在从网络流量中挑选出MPEG音频流,并尝试播放它们。 Driftnet是一款从网络流量捕获图像并将其显…

ARP中使用driftnet工具捕获图片

在进行任何网络攻防实验时&#xff0c;请务必遵守当地法律法规以及道德准则&#xff0c;必须遵守法律规定&#xff0c;只能在合法授权的情况下进行实验和演练。 预备知识 基本网络概念&#xff1a;了解TCP/IP协议、IP地址、MAC地址等基本网络概念。 ARP协议&#xff1a;了解A…

使用Arp欺骗与driftnet工具监听局域网信息

【重点声明】此系列仅用于工作和学习&#xff0c;禁止用于非法攻击&#xff0c;非法传播。一切遵守《网络安全法》 环境&#xff1a; Ubuntu 16.0.4攻击主机&#xff1a;192.168.1.130&#xff0c;Windows10 目标机&#xff1a;192.168.1.219 扫描该网段存活的主机&#xff1…

(arpspoof + driftnet)实现arp欺骗

(arpspoof driftnet)实现arp欺骗 虚拟机环境&#xff1a;kali linux window 7 文章目录 (arpspoof driftnet)实现arp欺骗前言一、安装arpspoof和driftnet二、Attack1.信息收集2.MAC欺骗与流量截图 总结 前言 ARP欺骗&#xff1a;欺骗局域网内主机的网关MAC地址&#xff0c…

自举电路介绍

自举电路也叫升压电路&#xff0c;利用自举升压二极管,自举升压电容等电子元件&#xff0c;使电容放电电压和电源电压叠加&#xff0c;从而使电压升高&#xff0e;有的电路升高的电压能达到数倍电源电压。 升压电路原理 举个简单的例子&#xff1a;有一个12V的电路&#xff0c…

秒懂电容自举电路

自举电容的核心原理是&#xff1a;电容两端电压不能突变。 从这句话中&#xff0c;我们可以获取到两个关键字&#xff1a;两端电压、不能突变。 两端电压指的是电容一边相对另一边的电压&#xff0c;我们知道电压本身就是个参考值&#xff08;一般认定参考GND&#xff0c;认定…

STM32自举程序

空间分布 将flash空间分为自举程序区和应用程序区。 应用程序区存放用户应用程序。 自举程序负责获取用户应用程序数据&#xff0c;并写入应用程序区&#xff0c;实现程序升级。 程序跳转 自举程序需要可以跳转到应用程序区&#xff0c;当然应用程序也可以根据需要设计成可…

自举电路(升压电路)

the boost converter,或者叫step-up converter&#xff0c;是一种开关直流升压电路&#xff0c;它可以是输出电压比输入电压高。基本电路图见图1.假定那个开关(三极管或者mos管)已经断开了很长时间&#xff0c;所有的元件都处于理想状态&#xff0c;电容电压等于输入电压。下面…

Web精美个人网页静态展示

今天和大家分享一个纯用web&#xff08;htmlcssjs&#xff09;实现的一个优美的个人信息菜单资料展示。 项目结构很简单只有一个html文件一个css样式文件以及一个js脚本文件。 项目实现的功能&#xff1a; 1&#xff1a;进入首页是一个天气样式页面&#xff08;显示当前时间…

【测控电路】自举式高输入阻抗放大电路

ref 测控电路第五版 有些传感器输出阻抗很高, 要求其测量放大电路有高输入阻抗. 开环集成运放的输入阻抗通常很高, 反相运放输入阻抗远低于同相运放, 为提高输入阻抗, 可在输入端加接电压跟随器, 但会引入共模误差. 在要求较高的场合下, 可采用高输入阻抗集成运放/采用通用运放…

自举电路工作原理分析

OTL功率放大器中要设自举电路,图18-9所示是自举电路。电路中的C1, R1和R2构成自举电路。C1为自举电容&#xff0c;R1O 隔离电阻&#xff0c;R2将自举电压加到 VT2基极。 向左转 | 向右转 VT1集电极信号为正半周期间VT2导通、放大&#xff0c;当输入VT2基极的信号比较大 时&…

STM32自举程序,你了解多少?

置顶/星标公众号&#xff0c;不错过每一条消息 本文主要讲述STM32启动模式中System memory的内容&#xff0c;以及围绕的相关内容。 1写在前面 STM32中内嵌了一段自举程序&#xff0c;可能很多人不知道。 那段自举程序存放在System memory&#xff08;系统存储器&#xff09;中…