Swift 类似HandyJSON解析Struct

article/2025/9/12 2:34:15

Swift 类似HandyJSON解析Struct

  • HandyJSON
  • 从源码解析Struct
    • 获取TargetStructMetadata
    • 获取TargetStructDescriptor
    • 实现TargetRelativeDirectPointer
    • FieldDescriptor和FieldRecord
    • fieldOffsetVectorOffset计算偏移量
  • 代码的验证

HandyJSON

HandyJSON是阿里开发的一个在swift上把JSON数据转化为对应model的框架。与其他流行的Swift JSON库相比,HandyJSON的特点是,它支持纯swift类,使用也简单。它反序列化时(把JSON转换为Model)不要求ModelNSObject继承(因为它不是基于KVC机制),也不要求你为Model定义一个Mapping函数。只要你定义好Model类,声明它服从HandyJSON协议,HandyJSON就能自行以各个属性的属性名为Key,从JSON串中解析值。不过因为HandyJSON是基于swiftmetadata来做的,如果swiftmetadata的结构改了,HandyJSON可能就直接不能用了。当然阿里一直在维护这个框架,swift的源码有变化,相信框架也是相对于有改变的。
HandyJSON的github

从源码解析Struct

获取TargetStructMetadata

由于HandyJSON是基于swiftmetadata来做的,说道解析解析struct,那就不得不去了解metadata。接下来,我们会从源码的角度去寻找metadata
首先,我们从源码Metadata.h中搜索StructMetadata相关信息,会发现其真正类型是TargetStructMetadata

using StructMetadata = TargetStructMetadata<InProcess>;

接着,我们查看TargetStructMetadata的结构会发现,TargetStructMetadata继承自TargetValueMetadataTargetValueMetadata继承自TargetMetadata

struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
struct TargetValueMetadata : public TargetMetadata<Runtime> {

那么,我们就可以通过这个继承链去还原TargetStructMetadata的结构。
从代码中我们可以看出,TargetStructMetadata的第一个属性是Kind,除了这个属性还有一个description,用于记录描述文件。

struct TargetMetadata {......private:/// The kind. Only valid for non-class metadata; getKind() must be used to get/// the kind value.StoredPointer Kind;......
}struct TargetValueMetadata : public TargetMetadata<Runtime> {using StoredPointer = typename Runtime::StoredPointer;TargetValueMetadata(MetadataKind Kind,const TargetTypeContextDescriptor<Runtime> *description): TargetMetadata<Runtime>(Kind), Description(description) {}//用于记录元数据的描述/// An out-of-line description of the type.TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;......
}

这样我们就可以得到TargetStructMetadata的结构为

struct TargetStructMetadata {// StoredPointer Kind; 64位系统下  using StoredPointer = uint64_t; 即为Intvar kind: Int  //暂且先定义为UnsafeMutablePointer,后面会分析typeDescriptor的结构 T就是泛型var typeDescriptor: UnsafeMutablePointer<T>
}

获取TargetStructDescriptor

接下来我们解析Description的相关信息。从源码中可得TargetStructDescriptorDescription的结构。

  const TargetStructDescriptor<Runtime> *getDescription() const {return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description);}

我们查找TargetStructDescriptor可以得到,其继承自TargetValueTypeDescriptor,含有两个属性NumFields(记录属性的count)和FieldOffsetVectorOffset(记录属性在metadata中的偏移量)

class TargetStructDescriptor final: public TargetValueTypeDescriptor<Runtime>,public TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,TargetTypeGenericContextDescriptorHeader,/*additional trailing objects*/TargetForeignMetadataInitialization<Runtime>,TargetSingletonMetadataInitialization<Runtime>,TargetCanonicalSpecializedMetadatasListCount<Runtime>,TargetCanonicalSpecializedMetadatasListEntry<Runtime>,TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {....../// The number of stored properties in the struct./// If there is a field offset vector, this is its length.uint32_t NumFields; //记录属性的count/// The offset of the field offset vector for this struct's stored/// properties in its metadata, if any. 0 means there is no field offset/// vector.uint32_t FieldOffsetVectorOffset; //记录属性在metadata中的偏移量

TargetValueTypeDescriptor继承自TargetTypeContextDescriptorTargetTypeContextDescriptor含有三个属性:Name(类型的名称)、AccessFunctionPtr(指向此类型的元数据访问函数的指针)和Fields(指向类型的字段描述符的指针)。

class TargetValueTypeDescriptor: public TargetTypeContextDescriptor<Runtime> {
public:static bool classof(const TargetContextDescriptor<Runtime> *cd) {return cd->getKind() == ContextDescriptorKind::Struct ||cd->getKind() == ContextDescriptorKind::Enum;}
};
class TargetTypeContextDescriptor: public TargetContextDescriptor<Runtime> {
public:/// The name of the type.// 类型的名称TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;/// A pointer to the metadata access function for this type.////// The function type here is a stand-in. You should use getAccessFunction()/// to wrap the function pointer in an accessor that uses the proper calling/// convention for a given number of arguments.// 指向此类型的元数据访问函数的指针TargetRelativeDirectPointer<Runtime, MetadataResponse(...),/*Nullable*/ true> AccessFunctionPtr;/// A pointer to the field descriptor for the type, if any.// 指向类型的字段描述符的指针TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,/*nullable*/ true> Fields;......
}

TargetTypeContextDescriptor又继承自基类TargetContextDescriptorTargetContextDescriptor包含两个属性:Flags(用于表示描述context的标志,包含kindversion)和Parent(用于表示父类的context,如果是在顶层,则表示没有父类,则为NULL)。

/// Base class for all context descriptors.
template<typename Runtime>
struct TargetContextDescriptor {/// Flags describing the context, including its kind and format version.// 用于表示描述context的标志,包含kind和versionContextDescriptorFlags Flags;/// The parent context, or null if this is a top-level context.// 用于表示父类的context,如果是在顶层,则表示没有父类,则为NULLTargetRelativeContextPointer<Runtime> Parent;......
}

从这里开始,TargetStructDescriptor就已经明了了,我们就可以写出TargetStructDescriptor的相关结构,同时修正TargetStructMetadata中的泛型T。

struct TargetStructMetadata {var kind: Intvar typeDescriptor: UnsafeMutablePointer<TargetStructDescriptor>
}struct TargetStructDescriptor {// 用于表示描述context的标志,包含kind和versionvar flags: Int32 // ContextDescriptorFlags Int32// 用于表示父类的context,如果是在顶层,则表示没有父类,则为NULLvar parent: TargetRelativeContextPointer<UnsafeRawPointer> // Relative 相对地址// 类型的名称var name: TargetRelativeDirectPointer<CChar> // Relative 相对地址// 指向此类型的元数据访问函数的指针var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer> //  Relative 相对地址// 指向类型的字段描述符的指针var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor> //  Relative 相对地址// 记录属性的countvar numFields: Int32// 记录属性在metadata中的偏移量var fieldOffsetVectorOffset: Int32
}// 下面是一些属性的类型解析
/// Common flags stored in the first 32-bit word of any context descriptor.
// flags 就是 Int32
struct ContextDescriptorFlags {private:uint32_t Value;
}

实现TargetRelativeDirectPointer

对于相对地址TargetRelativeDirectPointer,我们从源码中搜索TargetRelativeDirectPointer可得出TargetRelativeDirectPointer就是RelativeDirectPointer

template <typename Runtime, typename Pointee, bool Nullable = true>
using TargetRelativeDirectPointer= typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;

接着在RelativePointer.h找到RelativeDirectPointer,发现RelativeDirectPointer继承自基类RelativeDirectPointerImpl,其包含一个属性RelativeOffset(偏移量)。并且其含有通过偏移量获取真实内存的方法。

template <typename T, bool Nullable = true, typename Offset = int32_t,typename = void>
class RelativeDirectPointer;/// A direct relative reference to an object that is not a function pointer.
// offset传入Int32
template <typename T, bool Nullable, typename Offset>
class RelativeDirectPointer<T, Nullable, Offset,typename std::enable_if<!std::is_function<T>::value>::type>: private RelativeDirectPointerImpl<T, Nullable, Offset>
{......
}/// A relative reference to a function, intended to reference private metadata
/// functions for the current executable or dynamic library image from
/// position-independent constant data.
template<typename T, bool Nullable, typename Offset>
class RelativeDirectPointerImpl {private:/// The relative offset of the function's entry point from *this.Offset RelativeOffset;......// 通过偏移量计算 同时还返回泛型T类型PointerTy get() const & {// Check for null.if (Nullable && RelativeOffset == 0)return nullptr;// The value is addressed relative to `this`.uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset);return reinterpret_cast<PointerTy>(absolute);}......
}/// Apply a relative offset to a base pointer. The offset is applied to the base
/// pointer using sign-extended, wrapping arithmetic.
// 通过偏移量计算
template<typename BasePtrTy, typename Offset>
static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {static_assert(std::is_integral<Offset>::value &&std::is_signed<Offset>::value,"offset type should be signed integer");auto base = reinterpret_cast<uintptr_t>(basePtr);// We want to do wrapping arithmetic, but with a sign-extended// offset. To do this in C, we need to do signed promotion to get// the sign extension, but we need to perform arithmetic on unsigned values,// since signed overflow is undefined behavior.auto extendOffset = (uintptr_t)(intptr_t)offset;// 指针地址+存放的offset(偏移地址) -- 内存平移获取值return base + extendOffset;
}

那么我们就可以TargetRelativeDirectPointer的结构:

// 传入泛型Pointee
struct TargetRelativeDirectPointer<Pointee> {var offset: Int32// 通过偏移量计算内存mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee> {let offset = self.offsetreturn withUnsafePointer(to: &self) { p in// 使用advanced偏移offset,再重新绑定成Pointee类型return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self))}}
}

同时我们就可以修正TargetStructDescriptor为:

struct TargetStructDescriptor {// 用于表示描述context的标志,包含kind和versionvar flags: Int32// 用于表示父类的context,如果是在顶层,则表示没有父类,则为NULLvar parent: Int32// 由于不去解析,暂时定义为Int32// 类型的名称var name: TargetRelativeDirectPointer<CChar>// 指向此类型的元数据访问函数的指针var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>// 指向类型的字段描述符的指针var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>// 记录属性的countvar numFields: Int32// 记录属性在metadata中的偏移量var fieldOffsetVectorOffset: Int32
}// TargetRelativeContextPointer暂时不解析,通过源码分析可得暂时解析为Int32
template<typename Runtime,template<typename _Runtime> class Context = TargetContextDescriptor>
using TargetRelativeContextPointer =RelativeIndirectablePointer<const Context<Runtime>,/*nullable*/ true, int32_t,TargetSignedContextPointer<Runtime, Context>>;

FieldDescriptor和FieldRecord

再下一步,我们开始解析FieldDescriptor,源码中FieldDescriptor如下:

// Field descriptors contain a collection of field records for a single
// class, struct or enum declaration.
class FieldDescriptor {const FieldRecord *getFieldRecordBuffer() const {return reinterpret_cast<const FieldRecord *>(this + 1);}public:const RelativeDirectPointer<const char> MangledTypeName;const RelativeDirectPointer<const char> Superclass;FieldDescriptor() = delete;const FieldDescriptorKind Kind;const uint16_t FieldRecordSize;const uint32_t NumFields;......// 获取所有属性,每个属性用FieldRecord封装llvm::ArrayRef<FieldRecord> getFields() const {return {getFieldRecordBuffer(), NumFields};}......
}// FieldDescriptorKin就是 Int16
enum class FieldDescriptorKind : uint16_t {......
}

FieldRecord在源码中的结构为:

class FieldRecord {const FieldRecordFlags Flags;public:const RelativeDirectPointer<const char> MangledTypeName;const RelativeDirectPointer<const char> FieldName;......
}// Field records describe the type of a single stored property or case member
// of a class, struct or enum.
// FieldRecordFlags 就是Int32
class FieldRecordFlags {using int_type = uint32_t;......
}

fieldOffsetVectorOffset计算偏移量

最后还有fieldOffsetVectorOffset(记录属性在metadata中的偏移量)的计算,来获取属性再metadata中的偏移量。源码中能得到的资料是:

// StoredPointer 是Int32 即会返回一个Int32/// Get a pointer to the field offset vector, if present, or null.const StoredPointer *getFieldOffsets() const {assert(isTypeMetadata());auto offset = getDescription()->getFieldOffsetVectorOffset();if (offset == 0)return nullptr;auto asWords = reinterpret_cast<const void * const*>(this);return reinterpret_cast<const StoredPointer *>(asWords + offset);}

但是以这个逻辑去处理,获取的数据是不对的,所以我从HandyJSON的源码中找到了这个:

// 当时64位是 offset 会乘以2
return Int(UnsafePointer<Int32>(pointer)[vectorOffset * (is64BitPlatform ? 2 : 1) + $0])

分析到这里,我们就得到了一个比较清晰地结构线,如下:

// 通过偏移量计算内存地址 传入泛型Pointee
struct TargetRelativeDirectPointer<Pointee> {var offset: Int32// 通过偏移量计算内存mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee> {let offset = self.offsetreturn withUnsafePointer(to: &self) { p in// 使用advanced偏移offset,再重新绑定成Pointee类型return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self))}}
}struct TargetStructMetadata {var kind: Intvar typeDescriptor: UnsafeMutablePointer<TargetStructDescriptor>
}struct TargetStructDescriptor {var flags: Int32var parent: Int32var name: TargetRelativeDirectPointer<CChar>var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>var numFields: Int32var fieldOffsetVectorOffset: Int32func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer<Int32> {print(metadata)return metadata.assumingMemoryBound(to: Int32.self).advanced(by: numericCast(self.fieldOffsetVectorOffset) * 2)}// 计算元型时使用var genericArgumentOffset: Int {return 2}
}struct FieldDescriptor {var MangledTypeName: TargetRelativeDirectPointer<CChar>var Superclass: TargetRelativeDirectPointer<CChar>var kind: UInt16var fieldRecordSize: Int16var numFields: Int32var fields: FieldRecordBuffer<FieldRecord>
}struct FieldRecord {var fieldRecordFlags: Int32var mangledTypeName: TargetRelativeDirectPointer<CChar>var fieldName: TargetRelativeDirectPointer<UInt8>
}// 获取FieldRecord
struct FieldRecordBuffer<Element> {var element: Elementmutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {return withUnsafePointer(to: &self) {let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start inreturn start}return UnsafeBufferPointer(start: ptr, count: n)}}mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {return withUnsafePointer(to: &self) {return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))}}
}

代码的验证

下面我们就代码来验证我们得到的这个结构。

protocol BrigeProtocol {}extension BrigeProtocol {// 通过协议重新绑定类型 返回出去static func get(from pointor: UnsafeRawPointer) -> Any {// Self就是真实的类型pointor.assumingMemoryBound(to: Self.self).pointee}
}struct BrigeMetadataStruct {let type: Any.Typelet witness: Int
}func custom(type: Any.Type) -> BrigeProtocol.Type {let container = BrigeMetadataStruct(type: type, witness: 0)let cast = unsafeBitCast(container, to: BrigeProtocol.Type.self)return cast
}
// LLPerson结构体
struct LLPerson {var age: Int = 18var name: String = "LL"var nameTwo: String = "LLLL"
}
// 创建一个实例
var p = LLPerson()
// LLPerson的metadata按位塞入TargetStructMetadata这个metadata中,LLPerson.self就是UnsafeMutablePointer<TargetStructMetadata>.self
let ptr = unsafeBitCast(LLPerson.self as Any.Type, to: UnsafeMutablePointer<TargetStructMetadata>.self)// 拿到结构体名称
let namePtr = ptr.pointee.typeDescriptor.pointee.name.getmeasureRelativeOffset()
print("当前 struct name: \(String(cString: namePtr))")
// 拿到属性个数
let numFields = ptr.pointee.typeDescriptor.pointee.numFields
print("当前类属性个数: \(numFields)")// 拿到属性再metadata中的偏移量
let offsets = ptr.pointee.typeDescriptor.pointee.getFieldOffsets(UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self))print("----------- start fetch field -------------")for i in 0..<numFields {// 获取属性名let fieldName = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getmeasureRelativeOffset()print("----- field \(String(cString: fieldName))  -----")// 拿到属性对应的偏移量 按字节偏移的let fieldOffset = offsets[Int(i)]print("\(String(cString: fieldName)) 的偏移量是:\(fieldOffset)字节")// 这是swift混写过的类型名称 需要把它转成真正的类型名称let typeMangleName = ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.mangledTypeName.getmeasureRelativeOffset()
//    print("\(String(cString: typeMangleName))")let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)// 需要用到这个库函数 swift_getTypeByMangledNameInContext 传递四个参数let fieldType = swift_getTypeByMangledNameInContext(typeMangleName, // 混写过后的名称256,            // 混写过后的名称信息长度,需要计算 HandyJSON中直接 256UnsafeRawPointer(ptr.pointee.typeDescriptor), // 上下文 typeDescriptor中UnsafeRawPointer(genericVector).assumingMemoryBound(to: Optional<UnsafeRawPointer>.self)) //当前的泛型参数 还原符号信息// 将fieldType按位塞入Anylet type = unsafeBitCast(fieldType, to: Any.Type.self)// 通过协议桥接获取我们的真实类型信息let value = custom(type: type)//获取实例对象p的指针 需要转换成UnsafeRawPointer 并且绑定成1字节即Int8类型,//因为后面是按字节计算偏移量的,不转换,会以结构体的长度偏移let instanceAddress = withUnsafePointer(to: &p){return UnsafeRawPointer($0).assumingMemoryBound(to: Int8.self)}print("fieldTyoe: \(type) \nfieldValue: \(value.get(from: instanceAddress.advanced(by: Int(fieldOffset))))")
}print("----------- end fetch field -------------")

打印信息:
在这里插入图片描述
从内存地址我们也可以看出属性的布局信息。
在这里插入图片描述


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

相关文章

HandyJSON:Swift语言JSON转Model工具库

背景 JSON是移动端开发常用的应用层数据交换协议。最常见的场景便是&#xff0c;客户端向服务端发起网络请求&#xff0c;服务端返回JSON文本&#xff0c;然后客户端解析这个JSON文本&#xff0c;再把对应数据展现到页面上。 但在编程的时候&#xff0c;处理JSON是一件麻烦事。…

HandyJSON和SwiftyJSON的应用

2019独角兽企业重金招聘Python工程师标准>>> 1. HandyJSON的应用 想要通过HandyJSON实现序列化和反序列化, 必须实现HandyJSON协议, 不需要继承NSObject对象, 实现协议必须实现public init(){} 方法. 序列化和反序列化支持struct和enumerate类型. HandyJSON可支持非…

(时频分析学习)Week01:傅里叶级数,S变换与广义S变换

学习内容:了解了傅里叶变换相关内容,掌握了基本的傅里叶函数的性质、特性和背景。了解S变换和广义S变换的公式和具体含义。 s变换: (在"基准"论文中)意义: 公式: (傅里叶原公式),再有ω2πf 和 f(t)x(t)w(τ-t)进行转换 在另一篇论文中: 广义s变换: 加上了一点关…

解构变换矩阵:如何使变换矩阵分解为位移(T),旋转(R),缩放(S)矩阵

解构变换矩阵 给定一个转换的复合矩阵&#xff0c;关于组成该转换的任何单个转换的信息就会丢失。 我们如果有一个复合矩阵&#xff0c;怎么能使其分解为TRS三个矩阵呢&#xff1f;即如何完成下述变化&#xff1a; 其中M是给定的变换矩阵&#xff0c;T是平移矩阵&#xff0c;R是…

SS2022-Z变换-性质-什么是z变换的时移特性?

简 介&#xff1a; 本文介绍了z变换时移特性。 关键词&#xff1a; z变换&#xff0c;时移特性 #mermaid-svg-EnOHOPxDmWhoesDM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-EnOHOPxDmWhoesDM .error-icon{fill:#…

【转】传递函数中拉普拉斯变换的s是用来干什么的?

自控书里一上来就到处是s,这个s到底是个什么东西? 好我知道s是拉普拉斯变换出来的,但为什么要搞这样一个变换?这个s的物理意义是什么? 为什么传递函数的极点决定系统的性质? …… 要解答这些问题,首先要从拉普拉斯变换讲起。 -----------------------------------------…

S变换的Python代码

S变换的Python代码 S变换简介S变换Python程序 S变换简介 S变换&#xff0c;又称为Stockwell变换&#xff0c;由R. G. Stockwell于1996年提出。具体的定义如下&#xff1a; S变换在傅里叶域的表示形式为&#xff1a; 离散的S变换为&#xff1a; S变换克服了短时傅里叶变换固…

S变换画图

The S -transform with windows of arbitraryand varying shape 想画如上的三张图&#xff0c;可是问题 &#xff08;1&#xff09;滤波窗口的平滑实现 The filter (applied to the full 200£400 S-transform matrix)is constructed in Matlab by constructing a two-dime…

【广义S变换】一维广义S变换对非平稳信号处理的matlab仿真

1.软件版本 matlab2013b 2.本算法理论知识 参考文献: 《广义S变换时频分析的应用研究》 《时频分布与地震信号谱分析研究》 《非平稳信号广义S不变换及其在SAR图像分析中的应用研究》 《S变换时变滤波在去噪处理中的应用研究》 《广义S变换域时频特征分析及微弱目标检测…

频域/s域/z域三大变换的性质对比

本文主要介绍三大变换&#xff08;傅里叶变换、拉普拉斯变换及Z变换&#xff09;的性质对比及其常用信号变换。

S域到Z域变换和差分方程

1.s域的传递函数 G(s) 2 / (1500s 1) * exp(-100s) matlab 里面的命令是 sys tf(2,[1500,1],inputdelay,100) 得到 2 exp(-100*s) * ---------- 1500 s 1 2.求 Z域传递函数 dsy c2d(sys,10,z) % 10 为间隔采样时间 得到 0.01329 z^(…

matlab实现从s域变成z域、matlab实现长除法逆z变换实例

今天在复习微型计算机控制技术这门课时&#xff0c;感觉还是和当初学习时一样&#xff0c;计算量有点大。 主要是体现在&#xff1a;&#xff08;1&#xff09;、连续S域到离散Z域的变换。&#xff08;2&#xff09;、在画数字控制器和输出波形前对Y(z)和U(z)的长除法化简。 …

s域和z域变换笔记

连续函数 1、常见信号的拉普拉斯变换&#xff1a; 脉冲信号 δ&#xff08;t&#xff09;------------1 阶跃信号 μ&#xff08;t&#xff09;------------- 斜坡信号 t ------------------ 加速度信号 ---------------- 指数类信号 --------------- 正弦…

傅里叶变换(FS、FT、DTFT、DFT、DFS、FFT)、拉普拉斯变换和Z变换

傅里叶变换的目的&#xff1a;时域转为频域&#xff0c;滤波&#xff0c;求解微分方程等 1. FS&#xff08;Fourier Series&#xff09; 傅里叶级数&#xff1a;时域周期连续&#xff0c;频域离散。 前提&#xff1a;任何信号都可以看作是无限多的正弦波的叠加。 时域&#x…

Z变换

信号与系统的分析方法 可以分为两大类&#xff1a;时域分析和变换域分析 1.时域分析法&#xff1a; &#xff08;1&#xff09;连续时间信号与系统&#xff1a;信号的时域运算、分解&#xff0c;微分方程的经典解法&#xff1b;卷积积分 &#xff08;2&#xff09;离散时间…

matlab实现S域到Z域变换

传递函数如下: Z变换: 代码如下: %构造传递函数 h tf(10, [0.2 1 0]) %Z变换 zh c2d(h, 0.2,zoh) %得到分子分母系数 [num den] tfdata(zh, v) %得到零极点 [z, p, k] tf2zpk(num, den) 运行结果如下: h 10-----------0.2 s^2 sContinuous-time transfer functio…

S变换在特征提取中的使用

S变换 S变换采用高斯窗函数且窗宽与频率的倒数成正比&#xff0c;免去了窗函数的选择和改善了窗宽固定的缺陷&#xff0c;并且时频表示中各频率分量的相位谱与原始信号保持直接的联系&#xff0c;S变换具有良好的时频特性&#xff0c;适合用S变换对信号的一些时频与特征进行提取…

S变换

哈哈&#xff0c;这两天在整理时频分析的方法&#xff0c;大部分参考网上写的比较好的资料&#xff0c;浅显易懂&#xff0c;在这谢过各位大神了&#xff01; 今天准备写下S变换&#xff0c;由于网上资料较少&#xff0c;自己尝试总结下&#xff0c;学的不好&#xff0c;望各位…

S变化广义s变化和时频域特征-matlab

S变换(S-transform)最先出现是在1996年,由外国学者Stockwell提出,一般情况下,可以通俗的将S变换理解为小波变换和傅里叶变换的提升,充分弥补了傅里叶变换和小波变换所存在的不足之处,例如傅里叶变换的窗口尺度不可以随意改变,但是S变换就无此限制,与此同时,S变换还实…

S变换介绍(附代码)

1、S变换 作为小波变换和短时傅里叶变换的继承和发展&#xff0c; S 变换采用高斯窗函数且窗宽与频率的倒数成正比&#xff0c;免去了窗函数的选择和改善了窗宽固定的缺陷&#xff0c;并且时频表示中各频率分量的相位谱与原始信号保持直接的联系&#xff0c;使其在 PQD 分析中可…