分类 其它 下的文章

完结篇
:tarjan 求割点、点双连通分量、割边(桥)(附 40 道很好的 tarjan 题目)。

上一篇(tarjan 求强连通分量,缩点,求边双)



tarjan 求割点

还是
求强联通分量
的大致思路捏.

算法思路:

我们把图中的点分为两种: 每一个联通子图搜索开始的
根节点

其他点

判断是不是割点的方式如下:

  • 对于根节点

    记一下在跑 tarjan 过程中从这个点出发的未被搜索到的子节点的数量
    \(child\)
    ,如果
    \(child\ge 2\)
    ,那么这个点为割点,否则就不是割点;


    • 证明(很简单,建议自己先想一想为什么或者手模个图,实在不懂再看证明):

    设根节点为点
    \(u\)
    ,如果
    \(child\)
    为 1 的话,说明根节点的不同子树上的点可以不经过点
    \(u\)
    而互相到达,也就是说即使删了
    \(u\)
    点,图中所有点照样可以互相到达,则
    \(u\)
    不为割点。反之,同样也易证得为割点。

  • 对于其他点

    判断一个点
    \(u\)
    有没有一个子节点
    \(v\)
    使得
    low[v] >= dfn[u]
    ,若存在,则
    \(u\)
    为割点,否则不为割点。


    • 证明:

    因为我们在无向图中跑 tarjan 时,已经特判父节点或边的编号来避免走“回头路”了(详见上文求边双部分),所以如果满足判断条件时,说明
    \(v\)
    通过返祖边只能到达
    \(u\)
    及其子树部分,并不能到达
    \(u\)
    的祖先节点,所以若
    \(u\)
    点删去,那么
    \(v\)
    点便与
    \(u\)
    以上部分断开了,此时显然
    \(u\)
    为割点。

会判断这两类点是不是割点之后就做完了,相信大家也知道该怎么求了。看代码吧!

算法代码:

相比于求边双部分增加了数组
cut[x]
来判断
\(x\)
是不是割点,若为 true 则
\(x\)
是割点,否则不是。

void tarjan(int x, int p){
    low[x] = dfn[x] = ++th;
    s[++top] = x; int child = 0;
    for(int i=head[x]; i; i=nxt[i]){
        int y = to[i];
        if(y == p) continue;
        if(!dfn[y]){
            tarjan(y, x);
            low[x] = min(low[x], low[y]);

            if(low[y] >= dfn[x]){
                child++;
                if(p != 0 or child > 1) cut[x] = 1;
            }
        }
        else low[x] = min(low[x], dfn[y]);
    }
}

为什么
p == 0
说明
\(x\)
为根节点呢,大家肯定知道啦!

因为主函数中是这么写的:

    for(int i=1; i<=n; i++)
        if(!dfn[i]) tarjan(i, 0);



tarjan 求点双连通分量

我该先写求点双好呢还是先写求割边好呢,这俩都是需要割点的相关知识的,啊选择困难症(

但是的但是,学会求割点之后那求点双(简称 BCC)就很简单啦
啦啦小魔仙,玛卡巴卡,卡巴露露,摇身变!

算法思路:

性质:
无向连通图中割点一定属于至少两个BCC,非割点只属于一个BCC

如此图:2 号点是个割点,其他点则不是。有红、蓝两个 BCC。


有一条显然的结论:
每个点双,它在 dfs 时最先被发现的点一定是割点或者 dfs 树的树根

证明:这很显然吧?!根据割点的定义自己理解一下,不证明。算了,还是简单说一下吧:我们知道割点是 BCC 的交点,即 BCC 通过割点连接,从一个 BCC 到另一个 BCC 一定是从经过割点开始的,所以证得。

那么这条结论其实就等价于
每个 BCC 都在其最先被发现的点(一个割点或根节点)的子树中
。那么我们在上文求割点方法基础上每找到一个割点(或根节点)后,其子树(包含自己)便是一个点双连通分量了。

实现:

我们还是维护一个栈,存点,每当搜索到一个点时就将该点入栈,找到割点(就是找到一个 BCC)时将栈顶到该割点所有元素依次出栈,(但注意:割点并不出栈,因为上文已说一个割点属于两个 BCC,它还需要来更新另一个 BCC,所以先不出栈,特判就行。)那么出栈的元素以及割点就是所求的点双了。

算法演示:

如上图中,我们以 1 为根开始搜索;

搜索到 2 节点时,继续递归 2 -> 3 -> 4;发现
\(low_4 = 2 < dfn_3\)
,那么 3 号点则不是割点,回溯;


\(low_3 = dfn_2\)
,所以
\(2\)
号点是割点,那么将此时栈中从栈顶到
\(2\)
号点所有元素出栈形成点双;

此时栈从栈尾到栈顶依次是:1,2,3,4。那么便是 2,3,4 构成一个点双(但 2 还在栈中)。

继续回溯到 2 -> 1;发现 1 号点是根节点,也将栈中元素出栈(这时 1 是根节点,所以 1 也出栈),那么 1,2 就又构成了一个点双。


算法代码:

void tarjan(int x, int p){
    low[x] = dfn[x] = ++th;
    s[++top] = x;
    if(!p and !head[x]){ // 特判孤点
        BCC[++bcc].emplace_back(x);
        top--; return;
    }
    for(int i=head[x]; i; i=nxt[i]){
        int y = to[i];
        if(y == p) continue;
        if(!dfn[y]){
            tarjan(y, x);
            low[x] = min(low[x], low[y]);
            if(low[y] >= dfn[x] or !p){ //是割点或者根节点
                ++bcc;
                do BCC[bcc].emplace_back(s[top]);
                while(s[top--] != y);
                BCC[bcc].emplace_back(x);
            }
        }
        else low[x] = min(low[x], dfn[y]);
    }
}

例题:

【模板】点双连通分量

板子题练练手。注意这题需要判孤点情况。



tarjan 求割边(桥)

太简单啦!

和割点差不多,改一条:
low[y] > dfn[x]
,并且不需要特判根节点了(因为 边 != 点)。

解释:(在判边保证不走回头路的条件下)
\(low_y = dfn_x\)
时,说明不通过从
\(x -> y\)
这条路径,
\(y\)
也照样可以回到
\(x\)
节点,那么就保证从
\(y\)

\(x\)
有两条路径可走了,所以
\(x->y\)
这条路不是割边。

那么完了!

算法代码:

cut[i] = true;
表示
\(i\)
这条路为割边。

void tarjan(int x, int p){
    low[x] = dfn[x] = ++th;
    s[++top] = x;
    for(int i=head[x]; i; i=nxt[i]){
        int y = to[i];
        if(y == p) continue;
        if(!dfn[y]){
            tarjan(y, x);
            low[x] = min(low[x], low[y]);
            if(low[y] > dfn[x]){ 
                cut[i] = true;
            }
        }
        else low[x] = min(low[x], dfn[y]);
    }
}



题目练习:

这有个很好的
tarjan 题单
,从模板到进阶,题都很好,推荐给大家。

所含题目如下
P1656 炸铁路

P1455 搭配购买

P3916 图的遍历

P2835 刻录光盘

P1073 [NOIP2009 提高组] 最优贸易

P2863 [USACO06JAN]The Cow Prom S

P8436 【模板】边双连通分量

P8287 「DAOI R1」Flame

P2002 消息扩散

P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G

P3387 【模板】缩点

P3388 【模板】割点(割顶)

P8435 【模板】点双连通分量

P1407 [国家集训队]稳定婚姻

P2194 HXY烧情侣

P2746 [USACO5.3]校园网Network of Schools

P2812 校园网络【[USACO]Network of Schools加强版】

P2941 [USACO09FEB]Surround the Islands S

P2860 [USACO06JAN]Redundant Paths G

P3398 仓鼠找 sugar

P2169 正则表达式

P3627 [APIO2009] 抢掠计划

P2656 采蘑菇

P4306 [JSOI2010]连通数

P5676 [GZOI2017]小z玩游戏

P1656 炸铁路

P1455 搭配购买

P3916 图的遍历

P2835 刻录光盘

P1073 [NOIP2009 提高组] 最优贸易

P2863 [USACO06JAN]The Cow Prom S

P8436 【模板】边双连通分量

P8287 「DAOI R1」Flame

P2002 消息扩散

P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G

P3387 【模板】缩点

P3388 【模板】割点(割顶)

P8435 【模板】点双连通分量

P1407 [国家集训队]稳定婚姻

P2194 HXY烧情侣

P2746 [USACO5.3]校园网Network of Schools

P2812 校园网络【[USACO]Network of Schools加强版】

P2941 [USACO09FEB]Surround the Islands S

P2860 [USACO06JAN]Redundant Paths G

P3398 仓鼠找 sugar

P1262 间谍网络

P4742 [Wind Festival]Running In The Sky

P8867 [NOIP2022] 建造军营

P3469 [POI2008]BLO-Blockade

P2515 [HAOI2010]软件安装

P5058 [ZJOI2004]嗅探器

P7687 [CEOI2005] Critical Network Lines

P7924 「EVOI-RD2」旅行家

P5236 【模板】静态仙人掌

P3225 [HNOI2012]矿场搭建

P4716 【模板】最小树形图

P4126 [AHOI2009]最小割

P6335 [COCI2007-2008#1] STAZA

P4637 [SHOI2011]扫雷机器人

P5236 【模板】静态仙人掌

P4716 【模板】最小树形图

P4436 [HNOI/AHOI2018]游戏



End

历时多天,终于把这两篇 tarjan 写完了。

tarjan 都学了,那下一章包得是圆方树的啦(

\(敬请期待......\)

前言

.NET 8 的发布,微软推出了官方免费且开源的 Blazor UI 组件库 —— Fluent UI Blazor。

组件库提供了Web应用程序所需的工具,确保应用程序能够与 Microsoft 产品保持一致的外观和感觉。Fluent UI Blazor 不仅包含了对微软官方 Fluent UI Web Components 的封装,还提供了额外的组件和功能,简化开发流程,增强用户体验。

本文将介绍 Fluent UI Blazor 的特点和优势,以及帮助大家如何快速上手,利用这一强大的工具集来提升 Blazor 项目。

项目介绍

Blazor 是一个利用 C# 语言的强大框架,专门用于搭建交互式的 Web 应用程序。结合 Microsoft 的 Fluent UI 库,我们可以轻松创建既时尚又响应迅速的用户界面。

Microsoft Fluent UI Blazor 组件库专为 ASP.NET Core Blazor 应用程序设计,适用于 .NET 8 Blazor 项目。

若使用的是 .NET 6 或 7,请选用名为 Microsoft.Fast.Components.FluentUI 的 v3 版本。

Fluent UI Blazor 是微软官方推出的 UI 组件库,帮助我们搭建符合 Fluent 设计风格的应用程序,赋予应用现代 Microsoft 产品的外观和感觉。

该库不仅包含了微软官方 Fluent UI Web Components 的封装,还提供了额外的支持和组件,以便更好地利用 Fluent 设计系统,简化 Fluent UI 的集成过程。

项目特点

Blazor 是一个使用 .NET 框架和 C# 编程语言的 UI 框架,采用 Razor 语法来构建 Web 应用程序。

Blazor 支持开发单页应用(SPA)和 Web 服务,通过编译后的 C# 代码直接操作 HTML DOM,从而减少了对 JavaScript 的依赖。

其目标是让开发人员能够使用熟悉的 C# 语言编写 Web 应用程序,从而提高开发效率并降低学习成本。

  • Fluent 设计
    :组件遵循 Microsoft 的 Fluent 设计系统,提供现代且统一的用户界面。
  • 易于使用
    :通过 dotnet 模板或手动安装 NuGet 包,可以轻松集成 Fluent UI Blazor 组件到项目中。
  • 可定制性
    :基于 FAST(Adaptive UI)技术构建的组件支持高度定制和个人化,同时自动保持可访问性标准。
  • 附加包
    :提供了包含 Fluent UI 系统图标和表情符号的额外包,增强应用的视觉效果

项目源码

通过GitHub地址下载项目源码,选择不同版本的分支,进行Fluent UI Blazor 组件的学习和查阅,具体如下图所示:

项目使用

1、 创建 Blazor 项目

首先创建一个新的 Blazor Server 或 Blazor WebAssembly 项目,添加对应的 NuGet 包,然后将Fluent UI 集成到 Blazor。

2、创建一个示例数据源

在数据驱动的应用程序中,连接数据源是必不可少的步骤。

示例将使用内存中的数据服务来模拟数据源。创建一个 Services 文件夹,并添加 DataService.cs 文件,定义数据模型和获取数据的方法:

namespaceBlazorAppDemo.Services
{
/// <summary> ///数据服务/// </summary> public classDataService
{
/// <summary> ///产品数据/// </summary> private readonly List<Product> Products = new()
{
//模拟产品数据 new() { Id = 1, Name = "DotNet技术匠01", CreateTime =DateTime.Now },new() { Id = 2, Name = "DotNet技术匠02", CreateTime =DateTime.Now },new() { Id = 3, Name = "DotNet技术匠03", CreateTime =DateTime.Now },new() { Id = 4, Name = "DotNet技术匠04", CreateTime =DateTime.Now },new() { Id = 5, Name = "DotNet技术匠05", CreateTime =DateTime.Now }
};
/// <summary> ///获取产品列表/// </summary> /// <returns></returns> public List<Product>GetProducts()
{
returnProducts;
}
}
/// <summary> ///产品实体/// </summary> public classProduct
{
/// <summary> ///产品ID/// </summary> public int Id { get; set; }
/// <summary> ///产品名称/// </summary> public string Name { get; set; }
/// <summary> ///创建时间/// </summary> public DateTime? CreateTime { get; set; }
}
}

3、注册服务

在Program.cs 中注册服务,以便在应用中使用:

builder.Services.AddSingleton<DataService>();
builder.Services.AddSingleton
<IKeyCodeService, KeyCodeService>();

4、使用 Fluent UI 组件创建 UI

初始化的数据源已经设置好,接下来是创建用户界面。

打开 Pages 文件夹中的 Index.razor 文件,并替换其内容:

@page "/"
@using BlazorAppDemo.Services
@using Microsoft.Fast.Components.FluentUI
@inject DataService DataService
<FluentCard> <h3>产品列表</h3
<FluentStack
> <FluentDataGridItems="@products.AsQueryable()"TGridItem="Product"> <PropertyColumnProperty="@(p => p.Id)"Sortable="true" /> <PropertyColumnProperty="@(p => p.Name)"Sortable="true" /> <PropertyColumnProperty="@(p => p.CreateTime)"Format="yyyy-MM-dd hh:mm:ss"Sortable="true" /> </FluentDataGrid> </FluentStack> </FluentCard>
@code {
private List
<Product>products;

protected override void OnInitialized()
{
// 初始化时加载产品数据
products = DataService.GetProducts();
}
}

5、运行程序效果

打开浏览器,访问
https://localhost:xxxx
,我们就能够看到使用Fluent UI创建的产品列表。

UI组件展示

在线文档演示:
https://www.fluentui-blazor.net

通过访问在线文档的地址,查看每个组件的最终效果图以及组件代码的编写,可以方便我们快速查阅和学习,提高开发效率。

1、主题

2、表格

3、选择框

4、滑块

5、进度条

6、按钮

本文仅展示了部分组件,更多组件详情请访问在线文档地址进行查阅。文档中可以找到详细的组件列表、使用示例以及最佳实践,帮助大家充分利用 Fluent UI Blazor 的全部功能。

项目地址

GitHub:
https://github.com/microsoft/fluentui-blazor

在线文档:
https://www.fluentui-blazor.net

项目总结

通过结合 Blazor 的组件模型与 Fluent UI 强大的组件库,我们能够快速开发专业且现代的 Web 应用程序。

Blazor技术栈不仅简化了开发流程,还提供了高度的灵活性和可扩展性,以应对不断变化的用户体验需求。

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号
[DotNet技术匠]
社区,与其他热爱技术的同行一起交流心得,共同成长!
优秀是一种习惯,欢迎大家留言学习!

本篇是 Python 系列教程第 18 篇,更多内容敬请访问我的 Python 合集

1 打开文件

通常使用内置的
open(文件路径, 模式, encoding="utf-8")
函数。

  • 文件路径:可以是相对路径或绝对路径。
  • 模式:(可选)决定了文件打开后如何处理文件。
  • encoding:(可选)编码方式。

常见的模式有:

  • 'r' (默认):只读模式,如果文件不存在,则会引发 FileNotFoundError。
  • 'w':写入模式,如果文件存在则会清空内容再写入,如果文件不存在则创建新文件。
  • 'a':追加模式,在文件末尾追加内容,如果文件不存在则创建新文件。
  • 'b':二进制模式,用于处理二进制文件(如图像、音频等)。
  • '+':更新模式,用于同时进行读写操作。

可以将这些模式组合起来使用,例如:

  • 'rb':以二进制模式读取文件。
  • 'wb':以二进制模式写入文件。
  • 'ab':以二进制模式追加内容到文件。
  • 'r+':读写模式,可以读取和写入文件。
  • 'w+':写入并读取模式,先写入后读取。
  • 'a+':追加并读取模式,先追加后读取。

2 文件读取

如果
open()
函数执行成功,会返回一个文件对象。后续可以对这个对象进行读取或写入操作。

f = open('./data.txt', 'r', encoding='utf-8')

文件对象有个
read()
方法,会一次性读取文件里的所有内容,并返回字符串格式。

实例:

file = open('data.txt', 'r', encoding="utf-8")
print(file.read())

注意:

  • 如果调用过
    read()
    后再次调用,会返回空,因为程序会记录文件被读取的位置,第一次
    read()
    时已经读到文件末尾,第二次
    read()
    后面就没有内容了。
  • 大文件也不适合用
    read()
    ,因为会一次性读取文件的所有内容,可能挤爆内存。

上面说大文件不适合用
read()
,那有别的替换方案吗?当然有,解决方案就是一次性只读取部分内容,如:


  • read()
    传一个数字参数如
    read(1024)
    ,表示一次读多少字节,下次再调用
    read(1024)
    时就会继续从上次的结束位置读取。
  • 使用
    readline()
    ,此方法一次只会读取一行内容,是根据换行符来判断本行结尾的,而且换行符也会被当做内容的一部分被读取。

上面的两种方式可搭配
while
循环来用,另外还有一个
readlines()
方法,会一次性返回所有行,组成一个字符串列表,一般搭配
for
循环使用。

3 文件写入

调用
open()
函数时第二个参数传
w

a
就可以进行文件写入操作。这里说明一点,如果第二个参数是
r
,且文件不存在就会报
FileNotFoundError
错误,但是
w

a
就不会报错,它会自动创建一个文件。

在打开或创建文件之后就可以调用文件对象的
write()
方法进行写入操作了。

示例:

with open('data.txt', 'w', encoding="utf-8") as file:
    file.write("hello ")
    file.write("python")

data.txt内容:

hello python

注意
write()
方法并不会自动换行,需要手动添加换行符,如把代码改成
file.write("hello\n")
,data.txt就会变成:

hello
python

如果我们使用
w
模式,文件就只能写入不能读取,如果我们想先读取再写入,可以用
r+
模式

4 关闭文件

文件操作完毕后,文件对象需要调用一个
close()
方法关闭文件释放资源。

每次文件操作完毕后都应该关闭文件,但是有可能会粗心忘记关闭,怎么办呢?我们可以在调用
open()
函数打开文件的时候使用
with
关键字,然后用
as
指定读取到的文件,这样在
with
代码块执行完后文件就会被自动关闭了,实例:

# 使用 with 语句来读取文件
with open('data.txt', 'r', encoding='utf-8') as file:
    for line in file.readlines():
        print(line.strip())

开源地址

https://gitee.com/lboot/LLog

简介

LLog
是基于
AOP
构建的请求日志记录和查询工具库,通过引入该工具库,完成配置,实现对接口请求日志的记录、查询检索等功能。









准备

在引入任何
Lucy
系列依赖之前,需要完成
jitpack
镜像仓库的配置。

<repositories>
        <repository>
            <id>jitpack.io</id>
            <url>https://www.jitpack.io</url>
        </repository>
</repositories>

集成

引入


pom
中引入,版本号与
发行版本
一致。

<dependency>
        <groupId>com.gitee.lboot</groupId>
        <artifactId>LLog</artifactId>
        <version>0.0.8</version>
</dependency>

配置

1. 白名单配置

LLog
日志管理页面访问,默认仅支持
127.0.0.1
的请求来源访问(即支持本地访问),如果需要支持更多的访问来源,需要配置放行
IP
列表,通过
,
分隔。

# 日志请求白名单
llog.ip.allows=127.0.0.1,198.0.0.1

2. 数据库配置

LLog
基于
lucy-jpa
构建数据库访问,需要完成对应数据库配置。

# MySQL
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=demo
spring.datasource.password=
# JPA 允许结构替换
spring.main.allow-bean-definition-overriding=true
# 最小空闲连接数量
spring.datasource.hikari.minimum-idle=5
# 最长生命周期
spring.datasource.hikari.max-lifetime=120000
# 空闲连接存活最大时间,默认600000(10分钟)
spring.datasource.hikari.idle-timeout=50000
# 连接池最大连接数,默认是10
spring.datasource.hikari.maximum-pool-size=20
# 此属性控制从池返回的连接的默认自动提交行为,默认值:true
spring.datasource.hikari.auto-commit=true
# 连接测试查询
spring.datasource.hikari.connection-test-query=SELECT 1
# jpa 配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=false
spring.jpa.database=MYSQL
#自动将驼峰命名转换为小写和下划线 userId -> user_id
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
#不加这句则默认为myisam引擎
spring.jpa.database-platform= org.hibernate.dialect.MySQL5InnoDBDialect

3. 鉴权方案配置

LLog
会记录用户ID和请求IP。如果需要获取到用户ID,则需要完成对鉴权服务的配置,拓展实现
AuthService
中的
isLogin

getUid
接口,或者直接引入
lucy-rbac
等实现方案。

推荐自定义实现

@Slf4j
@Service
@AllArgsConstructor
public class DemoAuthServiceImpl implements AuthService {
    @Override
    public Boolean isLogin() {
        // return StpUtil.isLogin(); // 使用 SaToken 
        return AuthService.super.isLogin();
    }

    @Override
    public String getUid() {
        // return StpUtil.getLoginIdAsString(); // 使用 SaToken 
        return null;
    }
}

使用

@ApiLog

通过自定义注解标记需要记录请求日志的接口,实现对接口请求的自动记录。

@ApiLog("追踪测试")
@GetMapping("trace")
@ApiOperation(value = "追踪ID测试")
public ResponseDTO<Object> testTrace(){
    //
}

@ApiLog
注解可配置项如下:

参数 类型 备注
value string 默认为请求所属模块名词
module string value 别名
ignoreResponse int 记录数据是否忽略响应结果,1为是,0为否
ignoreRequest int 记录数据是否忽略请求参数,1为是,0为否

管理面板

通过访问项目部署地址,进入日志查看管理页面。

http://localhost:8080/dashboard.html

支持多种条件的日志检索方式。

功能截图

1. 异常堆栈

2. 请求 & 响应数据

鼠标悬浮即可查看

3. 条件查询

条件组合查询

例如此处就是
状态
+
接口方法
组合查询,支持全部条件的组合。

关键词匹配检索

请求来源和请求参数都支持模糊查询匹配,
支持条件查询与模糊查询组合使用

更新日志

0.0.8

  • [特性] 更新了
    lucy-spring-boot-starter
    版本依赖
  • [新增] 支持了按照请求参数模糊匹配的功能
  • [修复] 修复了重置页码不变化的bug

更多...

技术支持

kindear@foxmail.com

liwen01 2024.09.08

前言

经过二十多年的发展,WiFi 在硬件能力、软件和算法、频谱资源、市场需求、电源与能效方面都有了很大的提升。所以我们能看到从最开始只有几 M 速率的 802.11b,发展到现在几十 G 速率的 WiFi6,WiFi7。

前面我们介绍了 802.11 b/g/n 的一些核心技术和基础概念,本章将介绍目前比较新的 WiFi5 和 WiFi6,以及在今年会发布的 WiFi7。

图片

  • WiFi4 (802.11n,2009)
    :首次引入 MIMO 和 40 MHz 频宽,基础的高效无线网络标准。
  • WiFi5 (802.11ac,2013)
    :更高数据速率,专注于 5 GHz 频段,适合高清流媒体和在线游戏。
  • WiFi6 (802.11ax,2019)
    :更高效率,适合密集设备环境,支持更低的延迟和更高的节能表现。
  • WiFi7 (802.11be,2024)
    :预计今年(2024)会发布的新一代标准,提供超高数据速率,支持更高带宽需求。

我们先回顾一下上一章已介绍过的 WiFi4,后面介绍的 WiFi5、WiFi6、WiFi7 实际也是从 WiFi4 基础上迭代发展出来的,它们也都支持向下兼容。

本章涉及到比较多之前已介绍过的知识,这里只进行概括描述,详细介绍可以参考前面文章:


wifi基础(一):无线电波与WIFI信号干扰、衰减


WiFi基础(二):最新WiFi信道、无线OSI模型与802.11b/g/n

(一) 802.11n (WiFi4)

图片

(1) OFDM

OFDM (Orthogonal Frequency-Division Multiplexing)
正交频分复用调制技术,将信号分成多个窄带子载波,每个子载波独立调制。子载波之间是相互正交的,避免了相互干扰。

优点:

  1. 抗多径干扰能力强,特别适用于室内无线环境。
  2. 频谱效率高,能够在有限频谱内传输更高的数据速率。

缺点:

  1. 对频率偏移和相位噪声敏感。
  2. 实现较为复杂,需要精确的同步。

(2) FEC

FEC (Forward Error Correction)
前向纠错技术,在数据传输过程中增加冗余信息,以便在接收端进行错误检测和修正,从而提高数据传输的可靠性。

优点:

  1. 提高数据传输的可靠性,降低重传率。
  2. 提高了在信道质量较差情况下的通信质量。

缺点:

  1. 增加了数据包的长度和编码复杂度。
  2. 导致带宽开销增加。

(3) MIMO

MIMO (Multiple Input Multiple Output)
技术通过在发送端和接收端使用多个天线来同时传输和接收多路数据流,从而显著提高数据传输速率和网络覆盖范围。

优点:

  1. 大幅提高了数据传输速率 (通过空间复用)。
  2. 增强了信号覆盖范围和信道容量。

缺点:

  1. 实现成本较高,需要额外的硬件支持 (如多天线)。
  2. 天线之间的相互干扰可能会降低性能。

(4) Short GI

Short GI (Short Guard Interval)
是指将 OFDM 符号之间的保护间隔 (Guard Interval) 从标准的 800ns 缩短为 400ns。保护间隔用于减少符号间干扰。

优点:
缩短保护间隔可以提高数据传输速率 (提高约 11%)。

缺点:
短保护间隔在多径效应严重的环境中可能会导致符号间干扰,反而降低性能。

(5) 40 MHz 频宽

802.11n 支持将两个 20 MHz 的频段合并为一个 40 MHz 的频段,从而提高数据传输带宽和速率。

优点:
通过增大频宽,数据传输速率可以翻倍。

缺点:

  1. 在 2.4 GHz 频段上,40 MHz 频宽容易导致与其他设备 (如蓝牙设备、微波炉)发生干扰,特别是在频谱资源紧张的环境中。
  2. 可能影响其他使用相邻频段的无线设备的正常工作。

通过这些技术,802.11n 在实际应用中达到了比之前标准更高的吞吐量和更稳定的连接,但也面临着复杂性增加和部分场景中干扰增加的问题。

(6) WiFi4 最大速率

数据子载波数 x 每个符号传输比特数 x 载波编码率 x 符号速率 x MIMO = 最大理论速率

108 * 6bit * 5/6 * 277.778 ksps *4 = 600Mbps

(二) 802.11ac(WiFi5)

图片

WiFi5 只支持 5GHz 频段,与 WiFi4 相比,有一个大的突破是使用了 MU-MIMO 技术。

(1) MU - MIMO 技术

(a) MIMO 基本原理

MIMO 通过使用多个天线在发送端和接收端同时发送和接收多路数据流,来增加数据传输速率和信号覆盖范围。

在传统的单用户 MIMO (SU-MIMO)中,一次只能为一个设备 (用户)提供多路数据流,所有的天线资源只服务于一个设备。

(b) MU-MIMO 的原理

MU-MIMO (Multi-User Multiple Input Multiple Output)
是 MIMO 的多用户版本,它允许路由器 (AP) 使用多个天线同时向多个设备 (用户) 传输数据。这种方式显著提高了网络的并发能力和频谱利用效率。

(c) 如何工作

  • 多个数据流
    :MU-MIMO 能够同时向多个设备发送不同的数据流,而不是像 SU-MIMO 那样一次只能向一个设备发送数据流。

  • 分配天线资源
    :MU-MIMO 技术根据设备的需求和信道状态,动态地分配天线资源,使得多个设备可以同时利用无线带宽。

  • 空间分集
    :利用空间分集技术,MU-MIMO 可以区分和识别空间中不同用户设备的信号,避免相互干扰。

(d) 优点

提高效率
:MU-MIMO 能够同时为多个设备提供数据服务,避免了设备之间的竞争,减少了空闲时间和通信延迟,尤其在高密度设备环境下 (如家庭、办公场所、公共场所)表现尤为明显。

增加吞吐量
:通过多设备同时传输,MU-MIMO 提高了总体的网络吞吐量,使得更多设备能够获得稳定的高数据速率。

改善用户体验
:减少了由于设备增多而导致的网络拥堵问题,特别是在多设备同时进行高带宽需求操作 (如视频流、在线游戏)时效果显著。

(e) 限制和挑战

设备支持:
MU-MIMO 需要路由器和客户端设备 (如手机、平板、笔记本电脑)同时支持该技术
。如果客户端不支持 MU-MIMO,无法受益于该技术。

物理限制
:MU-MIMO 的性能受限于设备的天线数量、天线间隔、以及环境的多径效应。一般家庭路由器可能只能同时支持2-4个设备的MU-MIMO。

复杂度
:由于需要同时管理多个用户的数据流,MU-MIMO 技术的实现复杂度较高,尤其是在动态环境中,信道状态会随时变化,需要更复杂的算法来维持高效传输。

(f) 与 SU-MIMO 的比较

SU-MIMO
:一次只能为一个用户提供多路数据流,适合单个设备高速传输。

MU-MIMO:
能够同时为多个用户提供多路数据流,更加高效地利用无线资源,适合多设备并发环境。

图片

WiFi5 Wave2 因为使用了 MU-MIMO, 实现了 WiFi 从 1 对 1 的传输,跨越到 1 对多的传输,但是这里需要注意,
在WiFi5 Wave2 中,只支持下行方向的 MU-MIMO 。

(2) 802.11Wave1 速率计算

Wave1 与 WiFi 相比,使用了 256-QAM 编码,也就是每个符号可以传输 8bit 数。信道绑定由原来的 40MHz,现在提升到了 80MHz,数据子载波数提升到了 234 个。

数据子载波数 x 每个符号传输比特数 x 载波编码率 x 符号速率 x MIMO = 最大理论速率

234 * 8bit * 5/6 * 277.778 ksps *3 = 1300Mbps

(3) 802.11Wave2 速率计算

Wave 2 可以最大支持 160MHz 的带宽,数据子载波的数量有 468 个,空间流由 wave1 的 3 个提升到了 4 个。

数据子载波数 x 每个符号传输比特数 x 载波编码率 x 符号速率 x MIMO = 最大理论速率

468 * 8bit * 5/6 * 277.778 ksps *4 = 3466.67Mbps

图片

在最新的一些资料上看,WiFi5 wave1 可以支持到 3.47Gbps, wave2 可以支持到最大速率 6.9Gbps。主要是支持的空间流数的增加和信道带宽的增加。

最大速率是需要 AP 和 STA 都要支持对应的标准协议,并且有对应的硬件支持(比如天线个数),如果 AP 有多天线且运行 802.11ac 协议,但 STA 只支持 802.11n,并且只有单天线,那最大也就只能支持一个空间流,实际最大速率与理论最大速率之间会有很大的差异。

(4)  802.11 Wave2 跨信道绑定

图片

我们看到 802.11ac Wave2 中,提供的信道有一个 80+80 的信道,它表示可以将不相邻的两个 80MHz 信道进行聚合绑定,使信道频宽变得更宽更灵活。该技术也应用到了后面更新的 WiFi6 和 WiFi7 标准中。

(三) 802.11ax (WiFi6)

WiFi6 是现在正在逐渐推广的一个标准,它同时支持 2.4GHz 和 5GHz 频段。与 WiFi4 和 WiFi5 相比,WiFi6 的关键技术有:
1024QAM、OFDMA多址,上下行MU-MIMO,空间复用、TWT 技术

图片

(1) OFDMA多址技术

OFDMA (Orthogonal Frequency Division Multiple Access 正交频分多址)
用于将无线信道划分为多个子信道 (也称为子载波),每个子信道可以被不同的用户同时使用。

这种技术在4G LTE 网络中已经广泛应用,现在也被引入到了 WiFi 中,以提高网络效率。

(a) OFDMA的工作原理:

信道划分:
在OFDMA中,整个 WiFi 信道被划分为多个较窄的子信道 (子载波),每个子载波可以携带一部分数据。

用户分配:
不同的用户可以同时使用这些子载波进行通信。例如,一个用户可以使用某些子载波,而另一个用户可以使用其他子载波,这样可以在同一时刻支持多个用户进行数据传输。

提高效率:
通过允许多个用户共享同一信道,OFDMA 减少了信道的闲置时间,并提高了频谱利用率。这对于高密度环境 (如体育场、会议室等) 尤为重要,因为它能显著减少用户之间的干扰和竞争。

(b) OFDMA的优势

低延迟:
OFDMA 减少了用户之间的竞争,因此可以降低网络延迟,特别是在高流量环境下。

高效频谱利用:
通过灵活地分配子载波,OFDMA 能够更高效地利用频谱资源,避免信道资源的浪费。

更好的服务质量 (QoS):
OFDMA 允许网络根据需求分配资源,从而可以为不同的应用提供更好的服务质量,如流媒体、视频会议等。

支持更多用户:
OFDMA 使得 802.11ax 能够支持更多的并发用户,而不会显著降低每个用户的带宽。

(2) 空间复用

空间复用 (Spatial Reuse)
是利用空间分隔来增加同一频谱资源使用效率的技术。具体而言,它允许多个设备在同一时间内通过同一信道进行通信,只要这些设备之间的物理距离足够远,不会相互干扰。

(a) 空间复用的工作原理

(I) BSS Coloring:

BSS (基本服务集)
:在 WiFi 网络中,每个接入点 (AP)及其关联的设备形成一个BSS。传统 WiFi 网络中,如果相邻的 BSS 使用相同的信道,它们之间的信号会相互干扰,导致设备不得不等待信道空闲。

BSS Coloring
:WiFi6 通过引入BSS Coloring (BSS上色)技术来区分相邻的 BSS。每个 BSS 可以被赋予一个“颜色”,以帮助设备识别信号是否来自同一 BSS 。如果信号来自不同的 BSS 且干扰较小,设备仍然可以传输数据,从而实现空间复用。

(II) 目标信噪比 (SNR)调整:

传统的 WiFi 网络中,设备会通过检测信道上的能量水平来决定是否可以发送数据。如果检测到某个信号能量超过一定阈值,就认为信道被占用。

在 WiFi6 中,通过调节信噪比阈值,允许设备在感知到相对较弱的干扰信号时继续传输数据。这种调整使得空间复用变得更加有效。

(III) 灵活的频谱使用:

WiFi6 允许更灵活的频谱使用,能够根据当前的网络环境动态调整。这意味着在同一信道上,多个 AP 可以更高效地分配资源,减少因相互干扰而导致的频谱浪费。

(b) 空间复用的优势

提高网络容量:
空间复用通过允许更多的设备同时在同一信道上进行通信,极大地提高了网络的总体容量。

减少等待时间:
由于设备可以更频繁地访问信道,因此可以减少数据传输的等待时间,提升整体网络效率。

优化高密度环境:
在用户设备密集的场景 (如大型会议、体育场等),空间复用能够显著减少干扰,提高每个用户的体验。

(3) TWT 目标唤醒时间技术

TWT (Target Wake Time)
允许设备与接入点 (AP) 之间协商唤醒时间,从而减少设备的电池消耗。TWT 是 WiFi 6 引入的一项重要创新技术,它在节能和网络效率方面具有显著的优势。

工作原理:

时间协商
:设备和 AP 协商一个 TWT 协议,确定设备何时可以进入休眠模式,以及何时需要唤醒以发送或接收数据。这个协商可以根据设备的使用模式、数据传输需求和电源管理策略进行定制。

节能
:通过 TWT,设备可以在不需要频繁通讯的情况下长时间保持休眠状态,仅在预定的时间唤醒以处理数据。这大大减少了设备的功耗,特别是对于电池供电的设备如手机、物联网设备和传感器等。

减少干扰
:TWT 还可以减少不同设备之间的信号干扰。因为设备在不同的时间段内唤醒和传输数据,多个设备不会在同一时间段争抢无线信道,从而提高了整体网络的效率。

TWT 的类型

TWT 可以分为以下两种类型:

单个TWT
:在这种模式下,设备和 AP 协商一个单独的唤醒时间表。例如,设备可能每隔一段时间唤醒一次,以发送或接收数据。

广播TWT
:在广播 TWT 模式下,AP 可以向多个设备发送一个统一的 TWT 调度表。这样多个设备可以在相同的时间段内唤醒,进行同步的数据传输。

TWT 的应用场景

物联网设备:
许多物联网设备需要长时间待机且偶尔传输少量数据,TWT 技术可以显著延长这些设备的电池寿命。

移动设备:
智能手机、平板等移动设备可以通过 TWT 在 WiFi连接期间节省电量,尤其是在后台数据传输较少的情况下。

(4) WiFi6 的优势

图片

WiFi6 与 WiFi5 相比,在
大带宽、高并发、低延时、低功耗
方面都有大幅度的提升。

大带宽
:WiFi6 可以支持到 160MHz 频宽的信道绑定,使用 1024-QAM 的编码,最大支持 8 路空间流,使 WiFi6 的理论最大速率达到了 9.6Gbps

高并发
:支持上下行 MU-MIMO 与上下行 OFDMA 两种多用户传输技术,减少多用户并行传输时的信道开销,提升多用户场景下的空间信道利用率,另外 WiFi6 每个 AP 支持 1024 个终端接入。

低延时
:通过 OFDMA 和 MU-MIMO 技术减少了设备之间的竞争时间,从而加快了数据传输速度。

低功耗
:通过 TWT 和 Beamforming(波束成形) 技术,减少设备唤醒次数和优化信号传输来降低 STA 设备端的功耗。

WiFi6 与移动通讯中的 5G 非常类似,正逐渐地被推广使用。

(四) 802.11be (WiFi7)

(1) WiFi7 的关键技术

(a) 更宽的信道带宽

320MHz带宽
:WiFi7 支持 320 MHz的超宽信道带宽,相较于 WiFi6 的最大 160 MHz,带宽翻倍。这种带宽的扩展使得数据传输速率大大提高。

信道聚合
:WiFi7 支持将多个非连续频段聚合为一个逻辑信道,从而进一步提高带宽利用率。

(b) 更高阶的调制技术

4096-QAM (4K-QAM)
:WiFi7 引入了更高阶的调制方式 4096-QAM,相比 WiFi6 的 1024-QAM,数据密度增加了 50%。这意味着在相同信道条件下,WiFi7 能够传输更多数据,从而提升整体吞吐量。

(c) 多链路操作 (Multi-Link Operation, MLO)

多链路聚合
:WiFi7 允许设备同时在多个频段 (例如2.4 GHz、5 GHz和6 GHz)上传输数据,最大化带宽利用率,并提高传输的稳定性和速度。

链路负载平衡
:MLO技术还能根据网络负载和干扰情况,动态选择最优链路进行数据传输,减少延迟和信道拥堵。

(d) 增强的 OFDMA 和 MU-MIMO

增强的 OFDMA (正交频分多址)
:WiFi7进一步优化了 OFDMA 技术,支持更多的子载波和更细粒度的频谱分配,从而提高多用户环境下的网络效率。

MU-MIMO (多用户多输入多输出)
:WiFi7 支持 32 个空间流 (相比 WiFi6 的 8 个),这意味着能够同时为更多设备提供高速连接,特别是在密集环境下。

(e) 极低延迟和时间敏感网络 (Time-Sensitive Networking, TSN)

低延迟传输
:WiFi7 通过改进的调度算法和更灵活的频谱管理,实现了极低的传输延迟,非常适合需要高实时性的数据传输场景,如 AR/VR 和工业自动化。

TSN 支持
:WiFi7 引入了时间敏感网络支持,能够在无线网络中提供类似于有线网络的时间敏感数据传输,确保关键任务数据的稳定传输。

(f) 改进的BSS Coloring技术

增强的BSS Coloring
:WiFi7 进一步改进了 BSS Coloring 技术,使其在高密度网络环境下更有效地减少干扰,并提高信道复用效率。

(2) WiFi7 的理论最大速率

通过上述技术的综合应用,WiFi7 的理论最大速率可以达到 46 Gbps,这是WiFi6最大速率的近5倍。这种速度提升主要得益于更宽的信道带宽 (320 MHz)、更高阶的调制 (4096-QAM) 和多链路操作 (MLO)等技术的结合。

(五) WiFi 依然面临的问题

虽然 WiFi 技术在不断地发展,但是需要面对的问题也会越来越多。多用户并发、视频媒体重度发展、新老标准协议并存、各式物联网设备对 WiFi 实时性、功耗的不同要求,等等。

(1) 信号干扰与拥堵:

随着无线设备的普及,WiFi 信号的干扰会更加明显,办公区、商场、会展中心等环境经常会遇到各种问题,比如:能搜到 WiFi 热点,但却连接不上,就算连接上了,网速也很慢。

WiFi 热点众多,楼上楼下周围邻居间相互干扰,新老设备运行不同协议标准,多用户同时并发,导致信号干扰和拥堵明显。

(2) 带宽限制与速率瓶颈:

视频媒体重度发展,对高带宽、低延迟有极大的需求。尽管新的 WiFi 标准 (如 WiFi6 和 WiFi7) 提供了更高的理论最大速率,但在现实环境中,带宽的限制和设备间的竞争仍然可能导致网络速度无法达到预期。

(3) 覆盖范围与信号衰减:

WiFi 信号的覆盖范围有限,尤其在有墙壁或其他障碍物的情况下,信号衰减显著,导致信号质量下降,需要通过增加路由器或使用中继器来扩展覆盖范围。

对于户外高温、雨淋等环境,对设备可靠性和稳定性要求又很高。

(4) 安全性问题:

虽然 WiFi 安全性不断提升 (例如 WPA3 标准) ,但仍然存在潜在的安全漏洞,如中间人攻击、密码破解等。此外,许多用户在安全配置上意识不足,也可能导致网络被未经授权的设备访问。

(5) 功耗与设备兼容性:

随着物联网设备的普及,WiFi 网络连接的设备类型和数量大幅增加。这些设备对功耗和兼容性的要求各不相同,可能导致网络效率降低或设备无法有效连接。

(6) 技术更新与过渡:

随着 WiFi 技术的快速发展,新旧标准的过渡带来了一定的兼容性问题。用户可能需要更新硬件设备才能完全利用新标准的优势,比如增加天线个数。

对于对成本敏感的物联网设备,它们奉行的原则大多都是够用就好,所以这个技术过渡期会比较漫长。

结尾

关于 802.11 WiFi 相关标准的简单介绍到这里就结束了,下一章我们将介绍 WiFi 的工作原理,以及 WiFi 的接入过程分析。

上面内容,如有错误,欢迎评论区提示指出,不胜感激。

------------------End------------------
如需获取更多内容
请关注 liwen01 公众号