目录

一、绘制史密斯坐标系

1.绘制坐标系区域

2.阻抗圆与阻抗弧关系 

3.绘制阻抗圆

4.绘制阻抗弧

5.史密斯圆图坐标系完整代码

6.坐标系效果图

二、 绘制点及曲线

1.计算并绘制点

2.连接点 绘制曲线

3.绘制点和曲线代码



观察史密斯圆图,主要绘制圆(阻抗圆)和弧(阻抗弧),其中阻抗圆代表阻抗实部real(取值[0, +无穷)),阻抗弧代表阻抗虚部imag(取值(-无穷, +无穷))

一、绘制史密斯坐标系

1.绘制坐标系区域

新建一个widget窗口或者mainwindow窗口,重写保护函数paintEvent(QPaintEvent *event)

绘制史密斯圆图坐标系区域(半径R的最大阻抗圆),选择屏幕正中央为圆心

void MyWidget::paintEvent(QPaintEvent *event)
{
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing, true);

    // 计算屏幕中间位置,以左上角为(0,0)坐标
	int width = this->width();
	int height = this->height();
	int radius = qMin(width, height) / 2 - 50;
	double center_x = width / 2;
	double center_y = height / 2;
	QPointF center(center_x, center_y);

	// 绘制圆形白色背景
	painter.setPen(Qt::NoPen);
	painter.setBrush(Qt::white);
	painter.drawEllipse(center, radius, radius);
    
    // 实线绘制最大区域
	painter.setPen(QPen(Qt::black, 1, Qt::SolidLine));
	painter.drawEllipse(center, radius, radius);
}

2.阻抗圆与阻抗弧关系 

观察发现

阻抗圆圆心坐标:(R - r, 0)即(x + R - r,y),都与(R,0)点相切,y轴不变

阻抗弧圆心坐标:(R,-r)即(x + R, y - r),都与(R,0)点相切,x轴不变

注:程序以左上角为(0,0),右下角方向均为正,和传统坐标系不一样

 从这篇文章得到以下信息

史密斯圆图和直角坐标系的转换

绘制阻抗圆  圆心(x + real/(1+real), y)  半径 1/(real+1)
绘制电抗弧  圆心(x + R,1/imag)        半径 1/imag

推断出:当绘制同样半径大小的圆时 real + 1 = imag

   绘制同一半径r,得出以下关系

半径r 阻抗圆x值(y不变) 实部 虚部 阻抗弧y值(x不变)
r=1/10R center_x + R - 1/10R real=9 imag=10 center_y - r
r=1/5R center_x + R - 1/5R real=4 imag=5 center_y - r
r=1/2R center_x + R - 1/2R real=1 imag=2 center_y - r
r=2/3R center_x + R - 2/3R real=1/2 imag=3/2 center_y - r
r=5/6R center_x + R - 6/5R real=1/5 imag=6/5 center_y - r


3.绘制阻抗圆

绘制阻抗圆,半径 r= 1/(real+1) *R

    // 阻抗圆  圆心(center_x + R - r, center_y) 半径 r = (1/(real+1)) * R
	std::vector<double> realVec = { 0, (double)1/5, (double)1/2, 1, 2 ,5 ,10 };
    
    // 虚线绘制,没有背景色
	painter.setPen(QPen(Qt::black, 1, Qt::DashLine));
	painter.setBrush(Qt::NoBrush);
	for (int i = 0; i < realVec.size(); i++) {
		double r = radius * (1 / (realVec[i] + 1));
		QPointF c(center_x + radius - r, center_y);
        // 绘制圆 和 文字
		painter.drawEllipse(c, r, r);
		painter.drawText(c.x() - r - 5, c.y() + 10, QString::number(realVec[i]));
	}


4.绘制阻抗弧

绘制阻抗弧,半径 r = (1 / imag) * R,其中阻抗弧是绘制圆的弧度

QRect rect(x, y, d, d);
painter.drawArc(rect, θ * 16, φ * 16); Qt 中的角度单位是以 1 / 16 为单位的

drawArc在长宽为d并且左上角坐标为(x,y)的矩形,以矩形中点为圆心,当前起始角度θ,沿顺时针方向绘制φ度的圆弧

painter.drawArc(rect, θ * 16, -φ * 16);

drawArc在长宽为d并且左上角坐标为(x,y)的矩形,以矩形中点为圆心,当前起始角度θ,沿逆时针方向绘制φ度的圆弧

其中theta>90°时,tanθ取值为负值;其中theta=90°时,tanθ等于无穷(非法数据)

再绘制负方向的阻抗弧,

矩阵位置改变,绘制起始角度和绘制方向改变

for (int i = 0; i < imagVec.size(); i++) {
		double r = radius * (1 / imagVec[i]);
		QRect rect2(center_x + radius - r, center_y, 2 * r, 2 * r);

		// 阻抗弧坐标系,与R阻抗圆相交  求角度2θ
		// tanθ = r/R = 1/imag  2 * θ = 2 * atan2(r, R) 反正切
		double tan = (1 / imagVec[i]);
		double theta = 2 * atan2(r, radius) * 180 / 3.1415926;

		painter.drawArc(rect2, 90 * 16, (180 - theta) * 16);

		// tan2θ = 2*tanθ/(1 - tanθ*tanθ)
		// 坐标(sqrt(1 / (1 + tan2θ * tan2θ)), tan2θ * x)
		double tan2 = 2 * tan / (1 - tan*tan);
		double x = sqrt(1 / (1 + tan2 * tan2)) * radius;

		if (theta < 89) {
			painter.drawText(center_x + x + 4, center_y + x*tan2 +12, "-" + QString::number(imagVec[i]) + "i");
		} else if (theta > 91) {
			painter.drawText(center_x - x - 18, center_y - x*tan2 + 12, "-" + QString::number(imagVec[i]) + "i");
		} else {
			painter.drawText(center_x, center_y + radius + 12, "-1i");
		}
	}

5.史密斯圆图坐标系完整代码

// MyWidget.h
#include <QWidget>
#include "ui_MyWidget.h"

#include <QPainter>
#include <QPen>
#include <QPoint>
#include <QPointF>
#include <QtCore\qmath.h>

class MyWidget : public QWidget
{
	Q_OBJECT

public:
	MyWidget(QWidget *parent = Q_NULLPTR);
	~MyWidget();

protected:
	void paintEvent(QPaintEvent *event) override;

private:
	Ui::MyWidget ui;
};



// MyWidget.cpp
void MyWidget::paintEvent(QPaintEvent *event)
{
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing, true);

	int width = this->width();
	int height = this->height();
	int radius = qMin(width, height) / 2 - 50;
	double center_x = width / 2;
	double center_y = height / 2;
	QPointF center(center_x, center_y);

	// 绘制圆形背景
	painter.setPen(Qt::NoPen);
	painter.setBrush(Qt::white);
	painter.drawEllipse(center, radius, radius);


	// 同半径 r: real + 1 = imag
	// 阻抗圆  圆心(center_x + R - r, center_y) 半径 r = (1/(real+1)) * R
	std::vector<double> realVec = { 0, (double)1/5, (double)1/2, 1, 2 ,5 ,10 };
	painter.setPen(QPen(Qt::black, 1, Qt::SolidLine));
	painter.setBrush(Qt::NoBrush);

	for (int i = 0; i < realVec.size(); i++) {
		double r = radius * (1 / (realVec[i] + 1));
		QPointF c(center_x + radius - r, center_y);
		painter.drawEllipse(c, r, r);
		painter.drawText(c.x() - r - 12, c.y() + 12, QString::number(realVec[i]));
	}


    // 绘制中间直线,即最大阻抗圆直径
	painter.drawLine(center_x - radius, center_y, center_x + radius, center_y);



	// 电抗弧  圆心(center_x + R, center_y - r) 半径 r = (1/imag) * R
	// 矩阵 (center_x + R - r, center_y - 2*r)  边长2*r
	std::vector<double> imagVec = { 10, 5, 3, 2, (double)3 / 2,(double)6 / 5, 1, (double)4 / 5, (double)3 / 5,(double)2 / 5,(double)1 / 5 };
	painter.setPen(QPen(Qt::black, 1, Qt::DashLine));

	for (int i = 0; i < imagVec.size(); i++) {
		double r = radius * (1 / imagVec[i]);
		//Qt 中的角度单位是以 1 / 16 度为单位的,因此在设置起始角度和弧度时需要将角度值乘以 16.
		QRect rect(center_x + radius - r, center_y - 2 * r, 2 * r, 2 * r);
		QRect rect2(center_x + radius - r, center_y, 2 * r, 2 * r);

		// 阻抗弧坐标系,与R阻抗圆相交  求角度2θ
		// tanθ = r/R = 1/imag  2 * θ = 2 * atan2(r, R) 反正切
		double tan = (1 / imagVec[i]);
		double theta = 2 * atan2(r, radius) * 180 / 3.1415926;
		painter.drawArc(rect, 270 * 16, -(180 - theta) * 16);
		painter.drawArc(rect2, 90 * 16, (180 - theta) * 16);

		// 实际值 求两圆交点  最大阻抗圆real = 0
		// tan2θ = 2*tanθ/(1 - tanθ*tanθ)
		// 坐标(sqrt(1 / (1 + tan2θ * tan2θ)), tan2θ * x)
		double tan2 = 2 * tan / (1 - tan*tan);
		double x = sqrt(1 / (1 + tan2 * tan2)) * radius;

		if (theta < 89) {
			painter.drawText(center_x + x , center_y - x*tan2 - 6, QString::number(imagVec[i]) + "i");
			painter.drawText(center_x + x + 4, center_y + x*tan2 +12, "-" + QString::number(imagVec[i]) + "i");
		} else if (theta > 91) {
			painter.drawText(center_x - x - 13, center_y + x*tan2 - 10, QString::number(imagVec[i]) + "i");
			painter.drawText(center_x - x - 20, center_y - x*tan2 + 15, "-" + QString::number(imagVec[i]) + "i");
		} else {
			painter.drawText(center_x, center_y - radius - 8, "1i");
			painter.drawText(center_x, center_y + radius + 12, "-1i");
		}
	}
}

6.坐标系效果图


二、 绘制点及曲线

1.计算并绘制点

 计算实际点值的位置,此时的输入阻抗实部为real,输入阻抗虚部为imag

通过三角函数公式 计算得到直角三角形的另外两边,已知sinθ值和直角三角形第三边r(左图)

观察得出此时A的x轴值,center_x + R - r - xA(直角三角形水平边 边长)(右图)

尝试绘制一些点来验证,效果如下:

void MyWidget::drawSmithCircle()
{
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing, true);

	int width = this->width();
	int height = this->height();
	int radius = qMin(width, height) / 2 - 50;
	double center_x = width / 2;
	double center_y = height / 2;
	QPointF center(center_x, center_y);

	painter.setPen(QPen(Qt::red, 5, Qt::DashLine));
	

	// 阻抗圆  圆心(center_x + R - r, center_y) 半径 r = (1/(real+1)) * R
	// 电抗弧  圆心(center_x + R, center_y - r) 半径 r = (1/imag) * R
	std::vector<double> realV = { 0.2, 0.5, 0.5, 1, 2, 1.5 }; // 4 1 1/2
	std::vector<double> imagV = { -1, 1, -0.8, 0.8, 3, 0.4 };
	int size = realV.size();
	if (size < imagV.size()) 
		size = imagV.size();
	double real_r = 0, imag_r = 0;
	for (int i = 0; i < size; i++) {
		double real = realV[i];
		double imag = imagV[i];
		real_r = (1 / (real + 1)) * radius;
		if (imag != (double)0) 
			imag_r = (1 / imag) * radius;
		
		// 实际值 求两圆交点  point_y = sin2α*real_r
		// sin2α = 2cosαsinα = 2*real_r*imag_r/(pow(real_r) + pow(imag_r))
		double sin2 = 2 * real_r * imag_r / (real_r * real_r + imag_r * imag_r);
		double point_y = sin2 * real_r;
		double point_x = sqrt(real_r * real_r - point_y * point_y);
		painter.drawPoint(center_x + radius - real_r - point_x, center_y - point_y);
	}
}

2.连接点 绘制曲线

    QVector<QPointF> curvePoints;  // 点
	
	for (int i = 0; i < size; i++) {
		...
        ...

		double x = center_x + radius - real_r - point_x;
		double y = center_y - point_y;
		painter.drawPoint(center_x + radius - real_r - point_x, center_y - point_y);
		curvePoints.append(QPointF(x, y));
	}

	// 将点连接 绘制曲线
	painter.setPen(QPen(Qt::red, 2, Qt::SolidLine));
	painter.drawPolyline(curvePoints.data(), curvePoints.size());

 

3.绘制点和曲线代码

// 绘制反射系数点
void SmithChart::drawSmithCircle()
{
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing, true);

	int width = this->width();
	int height = this->height();
	int radius = qMin(width, height) / 2 - 60;
	double center_x = width / 2;
	double center_y = height / 2;
	QPointF center(center_x, center_y);

	painter.setPen(QPen(Qt::red, 5, Qt::DashLine));


	// 阻抗圆  圆心(center_x + R - r, center_y) 半径 r = (1/(real+1)) * R
	// 电抗弧  圆心(center_x + R, center_y - r) 半径 r = (1/imag) * R
	QVector<QPointF> curvePoints;
	//std::vector<double> realV = { 0.2, 0.5, 0.5, 1, 2, 1.5 }; // 4 1 1/2
	//std::vector<double> imagV = { -1, 1, -0.8, 0.8, 3, 0.4 };

	int size = realV.size();
	if (size < imagV.size())
		size = imagV.size();
	double real_r = 0, imag_r = 0;
	for (int i = 0; i < size; i++) {
		double real = realV[i];
		double imag = imagV[i];
		real_r = (1 / (real + 1)) * radius;
		if (imag != (double)0)
			imag_r = (1 / imag) * radius;

		// 实际值 求两圆交点
		// sin2α = 2cosαsinα = 2*real_r*imag_r/(pow(real_r) + pow(imag_r))
		// point_y = sin2α*real_r
		double sin2 = 2 * real_r * imag_r / (real_r * real_r + imag_r * imag_r);
		double point_y = sin2 * real_r;
		double point_x = sqrt(real_r * real_r - point_y * point_y);
		double x = center_x + radius - real_r - point_x;
		double y = center_y - point_y;

		painter.drawPoint(center_x + radius - real_r - point_x, center_y - point_y);
		curvePoints.append(QPointF(x, y));
	}

	// 绘制曲线
	painter.setPen(QPen(Qt::red, 2, Qt::SolidLine));
	painter.drawPolyline(curvePoints.data(), curvePoints.size());

}

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐