前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >张高兴的 .NET IoT 入门指南:(八)基于 GPS 的 NTP 时间同步服务器

张高兴的 .NET IoT 入门指南:(八)基于 GPS 的 NTP 时间同步服务器

作者头像
张高兴
发布于 2022-09-20 08:49:32
发布于 2022-09-20 08:49:32
3.3K00
代码可运行
举报
文章被收录于专栏:张高兴的博客张高兴的博客
运行总次数:0
代码可运行

时间究竟是什么?这既可以是一个哲学问题,也可以是一个物理问题。古人对太阳进行观测,利用太阳的投影发明了日晷,定义了最初的时间。随着科技的发展,天文观测的精度也越来越准确,人们发现地球的自转并不是完全一致的,这就导致每天经过的时间是不一样的。这点误差对于基本生活基本没有影响,但是对于股票交易、火箭发射等等要求高精度时间的场景就无法忍受了。科学家们开始把观测转移到了微观世界,找到了一种运动高度稳定的原子——铯,最终定义出了准确的时间:铯原子电子跃迁 9192631770 个周期所持续的时间长度定义为 1 秒。基于这个定义制造出了高度稳定的原子钟。

时间在计算机中又是如何定义的呢?通常使用 Unix 时间戳进行表示,记录的是自公元 1970 年 1 月 1 日 0 时 0 分 0 秒以来的秒数。计算机为了维持时钟的走时,硬件层面使用晶体振荡器保障时钟的精确性(也是石英钟的原理),操作系统层面使用时钟中断去更新时间的流逝。现代计算机的硬件设计通常有独立的时钟(RTC),这源于 Intel 和微软创立的标准 High Precision Event Timer(HPET),标准指定了 10 MHz 的时钟速度,因此时钟可以获得 100 纳秒的分辨率。这也是 .NET 时间有关的类型中 Ticks 属性的由来,1秒 = 10000000 Ticks。虽然计算机的时钟已经足够精准,但也会受到环境温度的影响造成过快或者过慢的问题。为了对计算机的时钟进行校准,通常使用 NTP 协议与网络中的时间服务器进行同步。时间服务器的时间又会使用 GPS 接收机、无线电或者是原子钟进行校准。

本文将从 GPS 时间的获取、NTP 报文的编写实现一个“玩具”级别的时间同步服务器,使用 .NET 6 编写一个控制台应用程序,通过本文你可以学到:

  1. 串口 SerialPort 类的使用;
  2. 使用 Socket 类实现 UDP 的监听与回复;
  3. 在程序中使用 Process 类执行命令行指令;
  4. 了解 GPS 数据报文的 NMEA-0183 协议;
  5. 了解 NTP 协议报文。
  • 硬件需求
  • 电路
  • GPS 数据报文的 NMEA-0183 协议
  • NTP 协议报文
  • 编写代码
    • 项目结构
    • 项目依赖
    • 配置串口读取 GPS 数据
    • 实现 NTP 服务
  • 部署应用
    • 发布到文件
    • 构建 Docker 镜像
  • 后续工作

硬件需求

名称

描述

数量

计算机

可以是运行 Linux 的开发板,也可以是运行 Windows 的电脑

x1

NEO-6M

GPS 模块

x1

USB 串口

可选,使用 USB 串口将 GPS 模块与计算机相连

x1

杜邦线

传感器与开发板的连接线

若干

电路

传感器

接口

开发板接口

NEO-6M

TX

开发板或 USB 串口的RX

RX

开发板或 USB 串口的TX

VCC

5V

GND

GND

GPS 数据报文的 NMEA-0183 协议

NMEA-0183 是 GPS 设备输出信息的标准格式,是由美国国家海洋电子协会(National Marine Electronics Association)定制的标准。NMEA-0183 有多种不同的数据报文,每种都是独立的 ASCII 字符串,使用逗号隔开数据,数据流长度从 30-100 字符不等,通常以每秒间隔选择输出。NMEA-0183 协议定义的语句非常多,但是常用的或者说兼容性最广的语句只有 GPGGA、GPGSA、GPGSV、GPRMC、

帧名称

说明

最大帧长

$GPGGA

全球定位数据

72

$GPGSA

卫星 PRN 数据

65

$GPGSV

卫星状态信息

210

$GPRMC

推荐最小数据

70

$GPVTG

地面速度信息

34

由于我们只需要从 GPS 中获取时间信息,选择包含时间信息的 “$GPRMC 推荐最小数据”帧进行解析:

$GPRMC

<1>

<2>

<3>

<4>

<5>

<6>

<7>

<8>

<9>

<10>

<11>

<12>*<13>

帧头

UTC 时间

定位状态

纬度

纬度半球

经度

经度半球

地面速率

地面航向

UTC 日期

磁偏角

磁偏角方向

模式 * 校验和

下面以一个真实的数据帧为例 $GPRMC,013717.00,A,3816.57392,N,10708.73951,E,0.467,,050722,,,A*78

$GPRMC

013717.00

A

3816.57392

N

10708.73951

E

0.467

050722

A*78

帧头

UTC 时间 01:37:17

A=有效定位,V=无效定位

纬度 38 度 16.57392 分

北纬

经度 107 度 8.73951 分

东经

地面速率 0.467 节

航向 度

UTC 日期 2022/07/05

磁偏角 度

磁偏角方向

A=自主定位,N=数据无效

因此,通过串口读取 $GPRMC 数据帧后,需要解析 <1><9> 字段的值,并将其转换为 UTC 时间。

细心的你也许会发现获取到的时间信息只精确到秒,GPS 明明使用的是原子钟,这是为什么?仔细观察手中的 GPS 模块,还有一个 PPS 针脚没有使用。PPS(Pulse Per Second)是秒脉冲,一般是由 GPS 接收机或原子钟按秒发出的、宽度小于1秒、有着急升或突降边沿的脉冲信号,通常用于精确计时和测量时间。PPS 信号能精确地(亚毫秒级)指示每一秒的开始时间,但不能指示对应现实时间的哪一秒,因此只能作为辅助信号,与卫星导航信息组合使用,提供低延迟、低抖动的授时服务。很遗憾,.NET 目前没法直接操作 PPS 引脚,我们只能实现一个“玩具”级的时间同步服务器了。

NTP 协议报文

NTP(Network Time Protocol),网络时间协议,是一种使用 UDP 的计算机之间进行时间同步的网络协议,位于 OSI 7 层网络模型中的应用层,默认使用的端口为 123。那么使用 NTP 是如何进行时间同步的呢?简单的说将发送的报文打上本机的时间戳,配合报文来回传输的时延修正本机的时间。如下图所示,可以计算出网络传输时延

\delta

,以及客户端与服务端的时间偏移

\theta

\delta=(t_3-t_0)-(t_2-t_1)
\theta=\frac{(t_1-t_0)+(t_2-t_3)}{2}

其中,

t_0

是请求报文传输的客户端时间戳,

t_1

是请求报文接收的服务器时间戳,

t_2

是回复报文传输的服务器时间戳,

t_3

是回复报文接收的客户端时间戳。客户端和服务端都有一个时间轴,分别代表着各自系统的时间,当客户端想要同步服务端的时间时,客户端会构造一个 NTP 报文发送到服务端,客户端会记下此时发送的时间

t_0

,经过一段网络延时传输后,服务器在

t_1

时刻收到报文,经过一段时间处理后在

t_2

时刻向客户端返回报文,再经过一段网络延时传输后客户端在

t_3

时刻收到服务器报文。这样客户端就可以校准自己的本机时间了。

在了解 NTP 同步时间的过程后,下面解析 NTP 报文具体包含的字段,一般的 NTP 报文长度为 48 字节:

字段

说明

LI

闰秒指示,2bit

Version

NTP 版本,3bit

Mode

工作模式,3bit ,客户端=0b011,服务器=0b100

Stratum

时钟层数,8bit,层数为 0 的设备为高精度的时钟(如原子钟),层数为 1 的设备与层数 0 的设备直接相连,……

Poll Interval

轮询时间,8bit,连续 NTP 报文之间的最大时间间隔

Precision

时钟精度,8bit

Root Delay

根时延,32bit,表示在主参考源之间往返的总共时延

Root Dispersion

根离散,32bit,相对于主参考源的标称误差

Reference ID

参考源的标识,32bit,4 个字符或 IP 地址

Reference Timestamp

参考时间戳,64bit,本地时钟最后一次被更新的时间

| Originate Timestamp | 原始时间戳

t_0

,64bit,客户端发送的时间 | | Receive Timestamp | 接受时间戳

t_1

,64bit,服务端接受到的时间 | | Transmit Timestamp | 传送时间戳

t_2

,64bit,服务端发送的时间 |

其中要注意的是 NTP 时间戳的起始时间是 1900-01-01 00:00:00,而不是 Unix 时间戳的起始时间 1970-01-01 00:00:00

下面是使用 Wireshark 抓取的 Windows 时钟同步的 NTP 报文:

编写代码

项目地址:https://github.com/ZhangGaoxing/gps-ntp

项目结构

创建一个控制台应用和类库,项目结构如下:

项目依赖

添加如下 NuGet 包引用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<ItemGroup>
   <PackageReference Include="System.IO.Ports" Version="6.0.0" />
</ItemGroup>

配置串口读取 GPS 数据

绝大部分 GPS 模块每秒会通过串口输出 NMEA-0183 协议报文,因此我们只需要通过串口读取需要的时间数据即可。此环节包含 3 个步骤:

  1. 初始化串口;
  2. 读取 $GPRMC 数据帧的内容,提取时间信息;
  3. 更新系统时间。
初始化串口

使用串口时最重要的属性是波特率,请查阅对应 GPS 模块的数据手册,这里使用的 NEO-6M 模块的波特率是 9600。串口的名称取决于你的连接方式,在 Linux 中串口对应的驱动文件在 /dev 目录下,使用内置串口可能的文件名称为 ttySx,使用 USB 串口可能的文件名称为 ttyUSBx,在 Windows 中串口的名称为 COMx,其中 x 表示的是数字编号。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 使用的串口名称
const string SERIAL_NAME = "/dev/ttyUSB0";
using SerialPort gps = new SerialPort(SERIAL_NAME)
{
    BaudRate = 9600,
    Encoding = Encoding.UTF8,
    ReadTimeout = 500,
    WriteTimeout = 500,
};
从串口中获取数据

从串口中读取数据时使用的是 SerialPort 类中的 DataReceived 事件。事件(event)可以理解为一种广播,当完成某种操作后向外发送通知。即串口接收到数据后,触发数据处理事件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gps.DataReceived += GpsFrameReceived;

/// <summary>
/// GPS 报文处理
/// </summary>
void GpsFrameReceived(object sender, SerialDataReceivedEventArgs e)
{
    // TODO:读取 `$GPRMC` 数据帧;提取时间;更新系统时间
}

由于 GPS 模块输出的不只有 $GPRMC 数据帧,因此需要在处理事件中判断帧头以及帧的有效性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void GpsFrameReceived(object sender, SerialDataReceivedEventArgs e)
{
    string frame = gps.ReadLine();

    if (frame.StartsWith("$GPRMC"))
    {
        // $GPRMC,UTC 时间,定位状态,纬度,纬度半球,经度,经度半球,速度,航向,UTC 日期,磁偏角,磁偏角方向,指示模式*校验和
        // $GPRMC,013717.00,A,3816.57392,N,10708.73951,E,0.467,,050722,,,A*78
        string[] field = frame.Split(',');

        // 帧数据有效
        if (!field[12].StartsWith("N"))
        {
            // TODO:提取时间;更新系统时间
        }
    }
}

在验证 $GPRMC 数据帧有效后,根据帧解析提取对应字段的时间信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void GpsFrameReceived(object sender, SerialDataReceivedEventArgs e)
{
    string frame = gps.ReadLine();

    if (frame.StartsWith("$GPRMC"))
    {
        string[] field = frame.Split(',');

        if (!field[12].StartsWith("N"))
        {
            // 获取 GPS 时间
            string time = field[1][0..6];
            string date = field[9];
            DateTime utcNow = DateTime.ParseExact($"{date}{time}", "ddMMyyHHmmss", CultureInfo.InvariantCulture);

            // TODO:更新系统时间
        }
    }
}
更新系统时间

由于 .NET 并不提供修改系统时间的操作,因此我们要使用间接的方式修改系统时间。一种方式是使用 P/Invoke 调用 C++ 的函数,这种方式可以精确的修改时间,但涉及引用、数据类型转换,过于复杂,和本入门指南不符。这里使用的是运行命令行指令的方式修改系统的时间,但修改时间的精度只能精确到秒。在 Windows 中使用 PowerShellSet-Date 命令,在 Linux 中使用 date 命令。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// 更新系统时间
/// </summary>
void UpdateSystemTime(DateTime time)
{
    ProcessStartInfo processInfo;
    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    {
        processInfo = new ProcessStartInfo
        {
            FileName = "powershell.exe",
            Arguments = $"Set-Date \"\"\"{time.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")}\"\"\"",
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true,
        };
    }
    else
    {
        processInfo = new ProcessStartInfo
        {
            FileName = "date",
            Arguments = $"-s \"{time.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")}\"",
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true,
        };
    }

    var process = Process.Start(processInfo);
    process.WaitForExit();
}

最终报文处理事件由以下代码构成:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void GpsFrameReceived(object sender, SerialDataReceivedEventArgs e)
{
    string frame = gps.ReadLine();

    if (frame.StartsWith("$GPRMC"))
    {
        string[] field = frame.Split(',');

        if (!field[12].StartsWith("N"))
        {
            string time = field[1][0..6];
            string date = field[9];
            DateTime utcNow = DateTime.ParseExact($"{date}{time}", "ddMMyyHHmmss", CultureInfo.InvariantCulture);

            UpdateSystemTime(utcNow);

            // 记录时钟最后一次被更新的时间
            lastUpdatedTime = utcNow;
        }
    }
}

使用 gps.Open(); 打开串口后就可以获取时间数据了。

实现 NTP 服务

下面使用 Socket 类实现一个简单的 UDP 服务器,用于监听和回复 NTP 报文。

初始化 UDP 服务
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// NTP 服务初始化
using Socket ntpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ip = new IPEndPoint(IPAddress.Any, 123);
ntpServer.Bind(ip);
监听和回复 NTP 报文

在后台新建一个进程用于监听 NTP 请求报文:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
new Thread(NtpFrameReceived)
{
    IsBackground = true
}.Start();

/// <summary>
/// NTP 报文接收与回复
/// </summary>
void NtpFrameReceived()
{
    // 存储接收到的 NTP 请求报文
    Span<byte> receiveFrame = stackalloc byte[48];

    while (true)
    {
        // 接收请求报文
        EndPoint clientPoint = new IPEndPoint(IPAddress.Any, 0);
        ntpServer.ReceiveFrom(receiveFrame, ref clientPoint);
        DateTime receiveTime = DateTime.UtcNow;

        // TODO:回复 NTP 报文
    }
}

根据帧解析生成 NTP 回复报文:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// 生成 NTP 报文
/// </summary>
Span<byte> GenerateNtpFrame(Span<byte> receivedFrame, DateTime receiveTime)
{
    Span<byte> ntpFrame = stackalloc byte[48]
    {
        0x1c, 0x01, 0x11, 0xe9, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    };

    // Client Transmit Timestamp => Server Origin Timestamp
    for (int i = 0; i < 8; i++)
    {
        ntpFrame[24 + i] = receivedFrame[40 + i];
    }

    // 本机时钟最后更新时间
    long referenceTicks = (lastUpdatedTime - ntpStart).Ticks;
    uint referenceTimeInt = (uint)(referenceTicks / TICK_2_SECOND);
    uint referenceTimeFract = (uint)(referenceTicks % TICK_2_SECOND);
    var referenceTimeIntByte = BitConverter.GetBytes(referenceTimeInt);
    var referenceTimeFractByte = BitConverter.GetBytes(referenceTimeFract);

    // 接收报文时间
    long receiveTicks = (receiveTime - ntpStart).Ticks;
    uint receiveTimeInt = (uint)(receiveTicks / TICK_2_SECOND);
    uint receiveTimeFract = (uint)(receiveTicks % TICK_2_SECOND);
    var receiveTimeIntByte = BitConverter.GetBytes(receiveTimeInt);
    var receiveTimeFractByte = BitConverter.GetBytes(receiveTimeFract);

    // 发送报文时间
    long transmitTicks = (DateTime.UtcNow - ntpStart).Ticks;
    uint transmitTimeInt = (uint)(receiveTicks / TICK_2_SECOND);
    uint transmitTimeFract = (uint)(receiveTicks % TICK_2_SECOND);
    var transmitTimeIntByte = BitConverter.GetBytes(receiveTimeInt);
    var transmitTimeFractByte = BitConverter.GetBytes(receiveTimeFract);

    if (BitConverter.IsLittleEndian)
    {
        for (int i = 0; i < 4; i++)
        {
            ntpFrame[19 - i] = referenceTimeIntByte[i];
            ntpFrame[23 - i] = referenceTimeFractByte[i];

            ntpFrame[35 - i] = receiveTimeIntByte[i];
            ntpFrame[39 - i] = receiveTimeFractByte[i];

            ntpFrame[43 - i] = transmitTimeIntByte[i];
            ntpFrame[47 - i] = transmitTimeFractByte[i];
        }
    }
    else
    {
        for (int i = 0; i < 4; i++)
        {
            ntpFrame[16 + i] = referenceTimeIntByte[i];
            ntpFrame[20 + i] = referenceTimeFractByte[i];

            ntpFrame[32 + i] = receiveTimeIntByte[i];
            ntpFrame[36 + i] = receiveTimeFractByte[i];

            ntpFrame[40 + i] = transmitTimeIntByte[i];
            ntpFrame[44 + i] = transmitTimeFractByte[i];
        }
    }

    return ntpFrame.ToArray();
}

最终报文请求与回复由以下代码构成:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void NtpFrameReceived()
{
    Span<byte> receiveFrame = stackalloc byte[48];

    while (true)
    {
        EndPoint clientPoint = new IPEndPoint(IPAddress.Any, 0);
        ntpServer.ReceiveFrom(receiveFrame, ref clientPoint);
        DateTime receiveTime = DateTime.UtcNow;

        // 回复 NTP 报文
        Span<byte> sendFrame = GenerateNtpFrame(receiveFrame, DateTime.UtcNow);
        ntpServer.SendTo(sendFrame, clientPoint);
        DateTime sendTime = DateTime.UtcNow;
    }
}

将上述代码进行整合就构成了基于 GPS 的 NTP 时间同步服务器。

部署应用

发布到文件

  1. 切换到 GpsNtp 项目运行发布命令:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dotnet publish -c release -r linux-x64 --no-self-contained
  1. 将发布后的文件通过 FTP 等方式复制到 Linux 开发板;
  2. GpsNtp 文件增加可执行权限
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sudo chmod +x GpsNtp
  1. 运行程序
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sudo ./GpsNtp

构建 Docker 镜像

  1. 在项目的根目录中创建 Dockerfile,并将整个项目复制到 Linux 开发板中:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
FROM mcr.microsoft.com/dotnet/core/sdk:6.0-focal AS build
WORKDIR /app

# publish app
COPY src .
WORKDIR /app/GpsNtp
RUN dotnet restore
RUN dotnet publish -c release -r linux-arm -o out

# run app
FROM mcr.microsoft.com/dotnet/core/runtime:6.0-focal AS runtime
WORKDIR /app
COPY --from=build /app/GpsNtp/out ./

ENTRYPOINT ["dotnet", "GpsNtp.dll"]
  1. 切换到项目目录,构建镜像:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
docker build -t gps-ntp -f Dockerfile .
  1. 运行镜像:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
docker run --rm -it --device /dev/ttySx gps-ntp

程序运行后,使用 Windows 时间同步服务进行一下测试。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-08-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
LLM 推理引擎之争:Ollama or vLLM ?
Hello folks,我是 Luga,今天我们来聊一下人工智能应用场景 - 构建高效、灵活的计算架构的模型推理框架。
Luga Lee
2025/04/24
1590
LLM 推理引擎之争:Ollama or vLLM ?
陈天奇等人新作引爆AI界:手机原生跑大模型,算力不是问题了
机器之心报道 机器之心编辑部 从此,大模型可以在任何设备上编译运行。 「我把大语言模型下到我的 iPhone 上,它神奇地跑起来了!」 五一假期还没过半,大模型领域的技术就已经发展到了这种程度。 对于陈天奇等人开源的新技术,大家一致的评论是「Amazing」。 最近人们都在研究 ChatGPT,大语言模型(LLM)彻底改变了科技领域的格局,但对于 AI 开发者来说,并不是人人都有上万块 A100 的。为了跑得起大模型,就要寻找各种优化方法。 在让大模型变小这条路上,人们做了很多尝试,先是 Meta 开源了
机器之心
2023/05/09
3950
陈天奇等人新作引爆AI界:手机原生跑大模型,算力不是问题了
A卡跑大模型,性能达到4090的80%,价格只有一半:陈天奇TVM团队出品
自预训练大模型兴起以来,人们面临的算力挑战就变得越来越大。为此,人们为大语言模型(LLM)提出了许多训练和推理的解决方案。显然,大多数高性能推理解决方案都基于 CUDA 并针对英伟达 GPU 进行了优化。
机器之心
2023/09/08
1.3K0
A卡跑大模型,性能达到4090的80%,价格只有一半:陈天奇TVM团队出品
浏览器就能跑大模型了!陈天奇团队发布WebLLM,无需服务器支持
金磊 发自 凹非寺 量子位 | 公众号 QbitAI 现在,只需一个浏览器,就能跑通“大力出奇迹”的大语言模型(LLM)了! 不仅如此,基于LLM的类ChatGPT也能引进来,而且还是不需要服务器支持、WebGPU加速的那种。 例如这样: 这就是由陈天奇团队最新发布的项目——Web LLM。 短短数日,已经在GitHub上揽货3.2K颗星。 一切尽在浏览器,怎么搞? 首先,你需要下载Chrome Canary,也就是谷歌浏览器的金丝雀版本: 因为这个开发者版本的Chrome是支持WebGPU的,否则就
量子位
2023/05/06
3820
浏览器就能跑大模型了!陈天奇团队发布WebLLM,无需服务器支持
MLC LLM——本地应用程序上原生部署任何语言模型
在AI浪潮风起云涌的当下,AI正在不断地重塑着每一个行业。在各大厂先后争先恐后地推出一系列大模型的同时,也不断出现了很多开源的大模型。今天介绍的这个出现在GitHub热榜上的项目是MLC LLM。它是一种通用解决方案,可以在各种硬件后端和本地应用程序上原生部署任何语言模型,同时为所有人提供一个高效的框架,以进一步优化模型性能以适应其自身的用例。 一切都在本地运行,无需服务器支持,并且可以在手机和笔记本电脑上通过本地GPU加速。
山行AI
2023/06/14
3.4K0
MLC LLM——本地应用程序上原生部署任何语言模型
陈天奇官宣新APP,让手机原生跑大模型,应用商店直接下载使用
前段时间,TVM、MXNET、XGBoost 作者,CMU 助理教授,OctoML CTO 陈天奇等多位研究者共同开发的一个项目引爆了 AI 界。
机器之心
2023/08/04
3670
陈天奇官宣新APP,让手机原生跑大模型,应用商店直接下载使用
LLM 大模型学习必知必会系列(一):大模型基础知识篇
2023 年,随着 LLM 技术的发展,中国模型研究机构的开源模型迎来了爆发式的增长:
汀丶人工智能
2024/05/11
3.2K0
LLM 大模型学习必知必会系列(一):大模型基础知识篇
RAG+AI工作流+Agent:LLM框架该如何选择,全面对比MaxKB、Dify、FastGPT、RagFlow、Anything-LLM,以及更多推荐
MaxKB = Max Knowledge Base,是一款基于 LLM 大语言模型的开源知识库问答系统,旨在成为企业的最强大脑。它能够帮助企业高效地管理知识,并提供智能问答功能。想象一下,你有一个虚拟助手,可以回答各种关于公司内部知识的问题,无论是政策、流程,还是技术文档,MaxKB 都能快速准确地给出答案:比如公司内网如何访问、如何提交视觉设计需求等等
汀丶人工智能
2024/08/05
11.1K0
RAG+AI工作流+Agent:LLM框架该如何选择,全面对比MaxKB、Dify、FastGPT、RagFlow、Anything-LLM,以及更多推荐
一文说明如何在NVIDIA Jetson上玩转大模型应用
非常兴奋能在这里与您分享一些关于将最新的生成式AI和大模型LLM引入边缘计算的惊人进展。
GPUS Lady
2023/11/13
3.1K0
一文说明如何在NVIDIA Jetson上玩转大模型应用
大模型时代的系统语言:Rust vs Mojo
这十七年我虽然没有什么光彩履历,但却很幸运,我还能在这个行业坚守,并能不断成长。同样很幸运,我经历了桌面软件没落, Web 2.0 崛起,以及移动互联网的兴盛,当下基础设施系统软件开始复兴的诸多历程。
张汉东
2023/09/13
2.4K0
大模型时代的系统语言:Rust vs Mojo
谷歌正式发布WebGPU!90多位贡献者研发6年,浏览器终于可以利用底层硬件了
整理 | 褚杏娟、核子可乐 经过六年的开发,当地时间 4 月 6 日,谷歌 Chrome 团队正式发布 WebGPU,用于在网络上进行高性能 3D 图形与数据并行计算。WebGPU 现已在 Beta 测试阶段的 Chrome 113 中默认启用。 WebGPU 是一种新型 Web 图形 API,具有显著减少同等图形规模下 JavaScript 工作量、将机器学习模型的推理效率提升 3 倍以上等优势。之所以能实现这样的飞跃,要归功于其令 WebGL 无法实现的灵活 GPU 编程和高级功能访问能力。 据悉,W
深度学习与Python
2023/04/10
1.3K0
谷歌正式发布WebGPU!90多位贡献者研发6年,浏览器终于可以利用底层硬件了
联邦语言模型:边缘SLM+云LLM
联邦语言模型是一个利用了两种人工智能趋势的想法:小型语言模型 (SLM) 和大型语言模型 (LLM) 能力的提升。
云云众生s
2024/07/14
3840
联邦语言模型:边缘SLM+云LLM
AutoGPT、AgentGPT、BabyAGI、HuggingGPT、CAMEL:各种基于GPT-4自治系统总结
来源:Deephub Imba本文约1400字,建议阅读5分钟集成ChatGPT和LLM到各种应用程序中只是使用语言模型的潜力的一部分。 ChatGPT和LLM技术的出现使得这些最先进的语言模型席卷了世界,不仅是AI的开发人员,爱好者和一些组织也在研究探索集成和构建这些模型的创新方法。各种平台如雨后春笋般涌现,集成并促进新应用程序的开发。 AutoGPT的火爆让我们看到越来越多的自主任务和代理利用了GPT-4的API。这些发展不仅增强了处理集成不同系统的复杂任务的能力,而且还推动了我们通过自主人工智能所能
数据派THU
2023/05/11
8950
AutoGPT、AgentGPT、BabyAGI、HuggingGPT、CAMEL:各种基于GPT-4自治系统总结
如何防止模型被窃取?基于TVM的端上模型部署加密方案
2023年在AI的发展史上一定是浓墨重彩的一笔,在这一年里出现了百模大战、全民“炼丹”的场面,围绕着各种模型的训练技术和算力需求有很多讨论。随着模型的成熟以及算力市场的发展,7B、13B这类小型号的模型也出现了端上部署的需求,其中以移动设备厂商最为突出。2024年,在端上部署和应用模型也可能会成为各家移动厂商的一个营销热点。
腾讯安全
2024/01/12
5080
如何防止模型被窃取?基于TVM的端上模型部署加密方案
GPT4All 3.0版 :66.5K 星星!最简单的本地 LLM 前端 - 无需 API 调用或 GPU、本地&私人
在人工智能领域,一年的时间可以带来巨大的变化。如果一个项目能存活超过一个月,那么它必定具有某些独特的优势。GPT4All 已经运行了一整年,仍然是 GitHub 上最受欢迎的项目之一。
AI进修生
2024/12/02
4790
GPT4All 3.0版 :66.5K 星星!最简单的本地 LLM 前端 - 无需 API 调用或 GPU、本地&私人
Ascend推理组件MindIE LLM
MindIE LLM是MindIE解决方案下的大语言模型推理组件,基于昇腾硬件提供业界通用大模型推理能力,同时提供多并发请求的调度功能,支持Continuous Batching、PageAttention、FlashDecoding等加速特性,使能用户高性能推理需求。
zjun
2024/12/04
1940
Ascend推理组件MindIE LLM
使用MLC-LLM将RWKV 3B模型跑在Android手机上(redmi k50每s可解码8个token
这篇文章主要是填一下 MLC-LLM 部署RWKV World系列模型实战(3B模型Mac M2解码可达26tokens/s) 这里留下来的坑,这篇文章里面介绍了如何使用 MLC-LLM 在A100/Mac M2上部署 RWKV 模型。但是探索在Android端部署一个RWKV对话模型的app时却碰到了诸多问题,解决的周期也很长,之前留了issue在MLC-LLM的repo,这周@chentianqi大佬回复说之前编译出的app会在模型初始化阶段卡住的问题已经解决了,所以我又重新开始踩了一些坑最终完成了在手机上运行RWKV World4 3B模型的目的。这里把踩的坑和Android编译方法都描述一下。
BBuf
2023/10/30
1.3K1
使用MLC-LLM将RWKV 3B模型跑在Android手机上(redmi k50每s可解码8个token
LLM推理提速2.8倍,CMU清华姚班校友提出「投机式推理」引擎SpecInfer,小模型撬动大模型高效推理
机器之心专栏 机器之心编辑部 近日,来自卡耐基梅隆大学(CMU)的 Catalyst Group 团队发布了一款「投机式推理」引擎 SpecInfer,可以借助轻量化的小模型来帮助大模型,在完全不影响生成内容准确度的情况下,实现两到三倍的推理加速。 随着 ChatGPT 的出现,大规模语言模型(LLM)研究及其应用得到学术界和工业界的广泛关注。一方面,开源的 LLM 模型不断涌现,比如 OPT、BLOOM、LLaMA 等,这些预训练模型的推出极大地促进了 LLM 的相关研究,使得 LLM 可以被应用于解决
机器之心
2023/05/31
1.3K0
LLM推理提速2.8倍,CMU清华姚班校友提出「投机式推理」引擎SpecInfer,小模型撬动大模型高效推理
mlc-llm 推理优化和大语言模型搭建解析(文末送书)
本文解析一下mlc-llm(https://github.com/mlc-ai/mlc-llm)对大模型推理的流程以及使用的图优化,算子优化策略。mlc-llm的模型部署流程可以查看官方文档:https://mlc.ai/mlc-llm/docs/ ,也可以参考我前段时间写的这篇MLC-LLM 部署RWKV World系列模型实战(3B模型Mac M2解码可达26tokens/s) 。
BBuf
2023/09/26
1.8K0
mlc-llm 推理优化和大语言模型搭建解析(文末送书)
WASM和机器学习
WebAssembly 是一种可以在现代Web浏览器中运行的低级的类汇编语言,具有紧凑的二进制格式,接近本机的性能运行的。为了实现代码紧凑WebAssembly 被设计成了不容易手写,但是支持C、C++、C#、Golang、Rust 等源语言编写代码,使用相应工具链翻译源语言代码。
thierryzhou
2022/11/18
1.1K0
推荐阅读
LLM 推理引擎之争:Ollama or vLLM ?
1590
陈天奇等人新作引爆AI界:手机原生跑大模型,算力不是问题了
3950
A卡跑大模型,性能达到4090的80%,价格只有一半:陈天奇TVM团队出品
1.3K0
浏览器就能跑大模型了!陈天奇团队发布WebLLM,无需服务器支持
3820
MLC LLM——本地应用程序上原生部署任何语言模型
3.4K0
陈天奇官宣新APP,让手机原生跑大模型,应用商店直接下载使用
3670
LLM 大模型学习必知必会系列(一):大模型基础知识篇
3.2K0
RAG+AI工作流+Agent:LLM框架该如何选择,全面对比MaxKB、Dify、FastGPT、RagFlow、Anything-LLM,以及更多推荐
11.1K0
一文说明如何在NVIDIA Jetson上玩转大模型应用
3.1K0
大模型时代的系统语言:Rust vs Mojo
2.4K0
谷歌正式发布WebGPU!90多位贡献者研发6年,浏览器终于可以利用底层硬件了
1.3K0
联邦语言模型:边缘SLM+云LLM
3840
AutoGPT、AgentGPT、BabyAGI、HuggingGPT、CAMEL:各种基于GPT-4自治系统总结
8950
如何防止模型被窃取?基于TVM的端上模型部署加密方案
5080
GPT4All 3.0版 :66.5K 星星!最简单的本地 LLM 前端 - 无需 API 调用或 GPU、本地&私人
4790
Ascend推理组件MindIE LLM
1940
使用MLC-LLM将RWKV 3B模型跑在Android手机上(redmi k50每s可解码8个token
1.3K1
LLM推理提速2.8倍,CMU清华姚班校友提出「投机式推理」引擎SpecInfer,小模型撬动大模型高效推理
1.3K0
mlc-llm 推理优化和大语言模型搭建解析(文末送书)
1.8K0
WASM和机器学习
1.1K0
相关推荐
LLM 推理引擎之争:Ollama or vLLM ?
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 硬件需求
  • 电路
  • GPS 数据报文的 NMEA-0183 协议
  • NTP 协议报文
  • 编写代码
    • 项目结构
    • 项目依赖
    • 配置串口读取 GPS 数据
      • 初始化串口
      • 从串口中获取数据
      • 更新系统时间
    • 实现 NTP 服务
      • 初始化 UDP 服务
      • 监听和回复 NTP 报文
  • 部署应用
    • 发布到文件
    • 构建 Docker 镜像
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档