fs = [(lambda n, i=i : i + n) for i in range(10)]

本文解释了Python中lambda表达式的使用方式,并通过实例展示了如何利用fs列表存储动态绑定的函数。此外,还介绍了map、reduce、filter和sort等Python内置函数的应用场景。

看Python中的lambda表达式,不免有很多人对一些文章中的这句不能理解。
相关链接

参考


我也困惑了一下,这里是我对它的理解。

>>>[a for a in range(5)]
[0,1,2,3,4]
#这个大家都能理解就是for每次遍历将其结果作为列表的输出
>>>a
4
#这种方式使用的变量可是全局变量,a=4
#因此这个表达式fs[3][8]=13我们能够理解了
#要记住此时生成的列表中都是函数,函数的参数是动态绑定的,运行时传入


#为什么这个可以?
fs = [(lambda n, i=i : i + n) for i in range(10)]
#另一个知识:默认参数在函数定义段被解析,且只解析一次 
>>>i = 5
>>>def f(arg=i):
>>>    print arg
>>>i = 6
>>>f()
5

#因此我们知道了,fs中的i在生成时绑定了循环中的i,不受最后的影响!

顺手补充下map/reduce/filter/sort这几个Python的常用函数

#map 对每个变量操作
>>> map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])
['1', '2', '3', '4', '5', '6', '7', '8', '9']

>>> map(lambda x:x**3,[x for x in range(5)])
[0, 1, 8, 27, 64]

#reduce把一个函数作用在一个序列[x1, x2, x3...]上,这个函数必须接收两个参数
>>> def fn(x, y):
...     return x * 10 + y
...
>>> def char2num(s):
...     return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
...
>>> reduce(fn, map(char2num, '13579'))
13579

#filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
>>> filter(lambda x:x%2 !=0 and x%3 !=0,range(2,25))
[5, 7, 11, 13, 17, 19, 23]

#lambda表达式在“:”后只能有一个表达式。也就是说,在def中,用return可以返回的也可以放在lambda后面,不能用return返回的也不能定义在python lambda后面。因此,像if或for或print这种语句就不能用于lambda中,lambda一般只用来定义简单的函数。
function [RD, r_axis, v_axis] = rd_ECABatch(surv, refsig, fs, b, K, N_range, N_doppler, fc) % rd_ECABatch — ECA-Batch 干扰抑制后的 Range-Doppler 图 % surv, refsig: 列向量输入;fs: 采样率;b: 分批数; % K: 干扰子空间大小;N_range, N_doppler: 输出图大小; % fc: 载波频率。 c = 3e8; % 光速 lambda = c/fc; % 波长 NB = floor(length(surv)/b); % 每批样本数 TB = NB/fs; % 每批时间长度 % 距离刻度 r_res = c/(2*fs); r_axis = (0:N_range-1)' * r_res; % 多普勒刻度(慢时域采样 fs_slow = 1/TB) fs_slow = 1/TB; f_res = fs_slow / N_doppler; f_axis = ((0:N_doppler-1) - N_doppler/2) * f_res; v_axis = (lambda/2) * f_axis; eps_reg = 1e-6; % 正则化因子 Cmat = zeros(N_range, b); % 预分配 for i = 1:b idx = (i-1)*NB + (1:NB); % 确保是列向量 x = surv(idx).'; % NB×1 y = refsig(idx).'; % NB×1 % 构造 NB×K 的干扰子空间矩阵 X X = zeros(NB, K); for k = 0:(K-1) X(k+1:NB, k+1) = y(1:NB-k); end % 最小二乘解 + 正则化 R_xx = X' * X + eps_reg * eye(K); w = R_xx \ (X' * x); % K×1 % 干净信号 s_eca = x - X * w; % NB×1 % slow-time cross-correlation C = xcorr(s_eca, y, NB-1, 'none'); % 取零延迟开始的 N_range 样点 Cmat(:, i) = C(NB : NB+N_range-1); end % 对每行(range bin)做 FFT → Doppler 维度 RD = fftshift( fft(Cmat, N_doppler, 2), 2 ); end % % function [RD, r_axis, v_axis] = rd_ECABatch(surv, refsig, fs, b, K, N_range, N_doppler, fc) % % c = 3e8; % lambda = c/fc; % % NB = floor(length(surv)/b); % TB = NB/fs; % % r_res = c/(2*fs); % r_axis = (0:N_range-1)' * r_res; % % fs_slow = 1/TB; % f_res = fs_slow / N_doppler; % f_axis = ((0:N_doppler-1) - N_doppler/2) * f_res; % v_axis = (lambda/2) * f_axis; % % eps_reg = 1e-6; % Cmat = zeros(N_range, b); % % for i = 1:b % idx = (i-1)*NB + (1:NB); % x = surv(idx).'; % y = refsig(idx).'; % % 构造干扰子空间 % X = zeros(NB, K); % for k = 0:(K-1) % X(k+1:end, k+1) = y(1:end-k); % end % % 投影子空间 % alpha = (X'*X + eps_reg*eye(K)) \ (X'*x); % clean = x - X*alpha; % % C = xcorr(clean, y, NB-1, 'none'); % Cmat(:, i) = C(NB:NB+N_range-1); % end % % RD = fftshift(fft(Cmat, N_doppler, 2), 2); % % end 这是我的eca部分
07-17
import tkinter as tk from tkinter import simpledialog, messagebox, filedialog, Menu import time import threading import html import uuid from datetime import datetime def render_html(content): content = content.replace("<br>", "\n") content = content.replace("<p>", "\n").replace("</p>", "") content = content.replace("<h1>", "\n🔥 ").replace("</h1>", "\n") content = content.replace("<h2>", "\n📌 ").replace("</h2>", "") content = content.replace("<", "<").replace(">", ">").replace("&", "&") return html.unescape(content) class Win12UltraVM: def __init__(self, root): self.root = root self.root.title("🌤️ Advanced Electronic Display OS v8.0 - Win12 Ultra (Light)") self.root.geometry("1300x900") self.root.configure(bg="#f3f3f3") # 浅色背景 self.root.resizable(True, True) # === 系统状态 === self.powered_on = False self.current_user = "User" self.clipboard = "" self.notification_log = [] self.browser_history = [] self.open_windows = {} # window_id: (window, cleanup_func) self.showing_app_drawer = False self.desktop_icons = [] # 字体(优先使用现代字体) self.font_ui = ('Segoe UI', 10) self.font_code = ('Consolas', 11) self.font_title = ('Bahnschrift', 14, 'bold') self.font_small = ('Segoe UI', 9) # 虚拟文件系统 self.filesystem = { "/": ["Documents", "Downloads", "Pictures"], "/Documents": ["readme.txt", "report.html"], "/Downloads": [], "/Pictures": [] } self.file_content = { "readme.txt": "欢迎使用 Win12 超复杂虚拟机。\n这是一个完全可交互的操作系统原型。", "report.html": "<h1>季度报告</h1><p>营收增长 15%</p><br><p>市场扩张至亚洲地区</p>" } self.recycle_bin = {} # 启动 self.boot_animation() # ======================== # 1. 开机动画(Win12 风格) # ======================== def boot_animation(self): self.splash = tk.Toplevel(self.root) self.splash.overrideredirect(True) w, h = 600, 350 x = (self.root.winfo_screenwidth() - w) // 2 y = (self.root.winfo_screenheight() - h) // 2 self.splash.geometry(f"{w}x{h}+{x}+{y}") self.splash.configure(bg="white") canvas = tk.Canvas(self.splash, bg="white", highlightthickness=0) canvas.pack(fill=tk.BOTH, expand=True) # Win12 徽标(四个圆环) self.rings = [] for i in range(4): x0, y0, x1, y1 = 250 + i * 25, 120, 290 + i * 25, 160 ring = canvas.create_oval(x0, y0, x1, y1, outline="#0078d7", width=6) self.rings.append(ring) label = tk.Label(self.splash, text="正在启动 Advanced OS v8.0...", fg="gray", bg="white", font=self.font_ui) label.place(relx=0.5, rely=0.7, anchor=tk.CENTER) self.animate_rings(canvas, 0) self.root.after(3500, self.finish_boot) def animate_rings(self, canvas, step): if not self.splash or not self.splash.winfo_exists(): return colors = ["#0078d7", "#e74856", "#107c10", "#ffb900"] for i in range(4): color = colors[(step + i) % 4] canvas.itemconfig(self.rings[i], outline=color) self.splash.update() if step < 16: self.root.after(200, lambda: self.animate_rings(canvas, step + 1)) def finish_boot(self): self.splash.destroy() self.powered_on = True self.setup_desktop() # ======================== # 2. 主桌面 # ======================== def setup_desktop(self): self.clear_root() self.root.configure(bg="#f3f3f3") # --- 任务栏 --- taskbar = tk.Frame(self.root, bg="#e0e0e0", height=40) taskbar.pack(side=tk.TOP, fill=tk.X, pady=0) taskbar.pack_propagate(False) start_btn = tk.Button(taskbar, text="⊞ 开始", bg="#0078d7", fg="white", font=self.font_ui, relief="flat", command=self.toggle_app_drawer) start_btn.pack(side=tk.LEFT, padx=10, pady=5) time_label = tk.Label(taskbar, text="", fg="black", bg="#e0e0e0", font=self.font_ui) time_label.pack(side=tk.RIGHT, padx=15) self.update_time(time_label) # --- 桌面区域 --- desktop_frame = tk.Frame(self.root, bg="#f3f3f3") desktop_frame.pack(fill=tk.BOTH, expand=True, padx=40, pady=40) self.create_desktop_icon(desktop_frame, "📄 记事本", self.open_notepad) self.create_desktop_icon(desktop_frame, "🌐 浏览器", self.open_browser) self.create_desktop_icon(desktop_frame, "⚙️ 设置", self.open_settings) self.create_desktop_icon(desktop_frame, "🧮 计算器", self.open_calculator) self.create_desktop_icon(desktop_frame, "🗑️ 回收站", self.open_recycle_bin) self.create_desktop_icon(desktop_frame, "📁 文件管理", self.open_file_manager) self.create_desktop_icon(desktop_frame, "📦 应用商店", self.open_store) self.create_desktop_icon(desktop_frame, "💬 AI助手", self.open_ai_assistant) # --- 状态栏 --- self.status_bar = tk.Label(self.root, text="🟢 系统运行中 | 用户: " + self.current_user, bg="#e8e8e8", fg="gray", font=self.font_small, anchor="w", height=2) self.status_bar.pack(side=tk.BOTTOM, fill=tk.X) self.status_bar.bind("<Button-1>", self.show_notifications) self.add_notification("系统已就绪。欢迎使用 Win12 超复杂虚拟机。") def update_time(self, label): if not self.powered_on: return t = time.strftime("%H:%M:%S") label.config(text=t) self.root.after(1000, lambda: self.update_time(label)) def create_desktop_icon(self, parent, text, cmd): frame = tk.Frame(parent, width=100, height=100) frame.pack_propagate(False) frame.pack(side=tk.LEFT, padx=25, pady=25) btn = tk.Button(frame, text=text, bg="white", fg="black", font=('Segoe UI Symbol', 9), relief="solid", bd=1, highlightbackground="#ddd", command=cmd, justify="center", anchor="center", padx=5, pady=5) btn.pack(fill=tk.BOTH, expand=True) btn.bind("<Enter>", lambda e: btn.config(bg="#f0f0ff", highlightbackground="#0078d7")) btn.bind("<Leave>", lambda e: btn.config(bg="white", highlightbackground="#ddd")) self.desktop_icons.append(btn) # ======================== # 3. 开始菜单 / 应用抽屉 # ======================== def toggle_app_drawer(self): if self.showing_app_drawer and hasattr(self, 'drawer') and self.drawer.winfo_exists(): self.drawer.destroy() self.showing_app_drawer = False else: self.drawer = tk.Toplevel(self.root) self.drawer.geometry("220x400+10+50") self.drawer.configure(bg="white") self.drawer.overrideredirect(True) self.drawer.attributes('-alpha', 0.95) title = tk.Label(self.drawer, text="📱 所有应用", bg="white", fg="black", font=self.font_title) title.pack(pady=10) apps = [ ("📄 记事本", self.open_notepad), ("🌐 浏览器", self.open_browser), ("⚙️ 设置", self.open_settings), ("🧮 计算器", self.open_calculator), ("🗑️ 回收站", self.open_recycle_bin), ("📁 文件管理", self.open_file_manager), ("📦 应用商店", self.open_store), ("💬 AI助手", self.open_ai_assistant), ("🔁 重启", self.reboot_system), ("⛔ 关机", self.shutdown_system), ] for name, cmd in apps: btn = tk.Button(self.drawer, text=name, bg="white", fg="black", font=self.font_ui, relief="flat", anchor="w", padx=15, command=cmd) btn.pack(fill=tk.X, pady=2, padx=5) btn.bind("<Enter>", lambda e, b=btn: b.config(bg="#e0e0ff")) btn.bind("<Leave>", lambda e, b=btn: b.config(bg="white")) self.showing_app_drawer = True # ======================== # 4. 新建通用窗口 # ======================== def new_window(self, title, width=800, height=600): win = tk.Toplevel(self.root) win.title(title) win.geometry(f"{width}x{height}") win.configure(bg="white") frame = tk.Frame(win, bg="white", padx=15, pady=15) frame.pack(fill=tk.BOTH, expand=True) window_id = str(uuid.uuid4()) self.open_windows[window_id] = (win, lambda: self.close_window(window_id)) win.protocol("WM_DELETE_WINDOW", lambda: self.close_window(window_id)) return window_id, win, frame def close_window(self, wid): if wid in self.open_windows: win, _ = self.open_windows[wid] win.destroy() del self.open_windows[wid] # ======================== # 5. 记事本 # ======================== def open_notepad(self): wid, win, frame = self.new_window("📄 记事本", 700, 500) text = tk.Text(frame, font=self.font_code, bg="white", fg="black", wrap=tk.WORD) text.pack(fill=tk.BOTH, expand=True) sb = tk.Scrollbar(text, command=text.yview) sb.pack(side=tk.RIGHT, fill=tk.Y) text.config(yscrollcommand=sb.set) menu = Menu(win, tearoff=0) menu.add_command(label="💾 保存", command=lambda: self.save_file_from_text(text)) menu.add_command(label="📋 复制", command=lambda: self.copy_text(text)) menu.add_command(label="✂️ 切除", command=lambda: self.cut_text(text)) menu.add_command(label="📌 粘贴", command=lambda: self.paste_text(text)) win.config(menu=menu) def save_file_from_text(self, widget): content = widget.get(1.0, tk.END).strip() fname = simpledialog.askstring("保存", "输入文件名:", initialvalue="new.txt") if fname: path = "/" # 默认根目录 self.filesystem[path].append(fname) self.file_content[fname] = content self.add_notification(f"✅ 已创建文件: {fname}") # ======================== # 6. 浏览器(多标签页) # ======================== def open_browser(self): wid, win, frame = self.new_window("🌐 浏览器", 900, 600) notebook = tk.Frame(frame, bg="white") notebook.pack(fill=tk.BOTH, expand=True) addr_frame = tk.Frame(notebook, bg="#f0f0f0", height=40) addr_frame.pack(fill=tk.X, pady=5) addr_frame.pack_propagate(False) url_var = tk.StringVar(value="about:start") entry = tk.Entry(addr_frame, textvariable=url_var, font=self.font_code) entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) entry.bind("<Return>", lambda e: self.load_webpage(url_var.get(), text_widget)) go_btn = tk.Button(addr_frame, text="前往", command=lambda: self.load_webpage(url_var.get(), text_widget)) go_btn.pack(side=tk.RIGHT, padx=5) text_widget = tk.Text(notebook, bg="white", fg="black", font=self.font_code, wrap=tk.WORD) text_widget.pack(fill=tk.BOTH, expand=True) sb = tk.Scrollbar(text_widget, command=text_widget.yview) sb.pack(side=tk.RIGHT, fill=tk.Y) text_widget.config(yscrollcommand=sb.set) self.load_webpage("about:start", text_widget) def load_webpage(self, url, text_widget): if url == "about:start": content = "📘 欢迎使用 WinBrowse\n\n- 输入网址浏览\n- 使用 file:// 访问本地文件" elif url.startswith("file://"): fname = url[7:] content = self.file_content.get(fname, "❌ 文件未找到") else: content = f"🌐 正在访问: {url}\n\n此为模拟浏览器,无真实网络连接。" text_widget.config(state=tk.NORMAL) text_widget.delete(1.0, tk.END) text_widget.insert(tk.END, content) text_widget.config(state=tk.DISABLED) # ======================== # 7. 设置中心 # ======================== def open_settings(self): wid, win, frame = self.new_window("⚙️ 设置", 600, 500) tk.Label(frame, text="🔧 系统设置", font=self.font_title, fg="#0078d7").pack(anchor="w", pady=10) settings = [ ("🎨 主题", "浅色模式"), ("🔊 音量", "75%"), ("🔆 亮度", "60%"), ("👤 用户", self.current_user), ("📡 网络", "Wi-Fi 已连接"), ("💾 存储", "211 GB 可用") ] for name, value in settings: row = tk.Frame(frame, bg="white") row.pack(fill=tk.X, pady=5) tk.Label(row, text=name, font=self.font_ui, width=15, anchor="w").pack(side=tk.LEFT) tk.Label(row, text=value, font=self.font_ui, fg="gray", anchor="w").pack(side=tk.LEFT, fill=tk.X) # ======================== # 8. 计算器 # ======================== def open_calculator(self): wid, win, frame = self.new_window("🧮 计算器", 300, 400) self.calc_input = tk.Entry(frame, font=self.font_code, justify='right', bg="#f9f9f9") self.calc_input.pack(fill=tk.X, pady=10) buttons = [ ['C', '±', '%', '÷'], ['7', '8', '9', '×'], ['4', '5', '6', '-'], ['1', '2', '3', '+'], ['0', '.', '='] ] for row in buttons: f = tk.Frame(frame, bg="white") f.pack(fill=tk.X) for txt in row: btn = tk.Button(f, text=txt, font=self.font_code, width=4, height=2, bg="white", command=lambda t=txt: self.calc_click(t)) btn.pack(side=tk.LEFT, padx=2, pady=2) def calc_click(self, char): if char == 'C': self.calc_input.delete(0, tk.END) elif char == '=': try: exp = self.calc_input.get().replace('×', '*').replace('÷', '/') result = eval(exp) self.calc_input.delete(0, tk.END) self.calc_input.insert(0, str(result)) except: self.calc_input.delete(0, tk.END) self.calc_input.insert(0, "错误") else: self.calc_input.insert(tk.END, char) # ======================== # 9. 回收站 # ======================== def open_recycle_bin(self): wid, win, frame = self.new_window("🗑️ 回收站", 500, 400) lb = tk.Listbox(frame, font=self.font_code) lb.pack(fill=tk.BOTH, expand=True) for name in self.recycle_bin.keys(): lb.insert(tk.END, name) tk.Button(frame, text="🗙 清空", command=lb.delete(0, tk.END)).pack(pady=5) tk.Button(frame, text="↩️ 还原", command=lambda: self.restore_file(lb)).pack(pady=5) def restore_file(self, lb): sel = lb.curselection() if sel: name = lb.get(sel[0]) path = "/" # 默认路径 if path not in self.filesystem: self.filesystem[path] = [] self.filesystem[path].append(name) self.file_content[name] = self.recycle_bin[name] del self.recycle_bin[name] lb.delete(sel[0]) self.add_notification(f"🔄 已还原文件: {name}") # ======================== # 10. 文件管理器 # ======================== def open_file_manager(self): wid, win, frame = self.new_window("📁 文件管理器", 600, 500) lb = tk.Listbox(frame, font=self.font_code) lb.pack(fill=tk.BOTH, expand=True) for path, files in self.filesystem.items(): lb.insert(tk.END, f"[{path}]") for f in files: lb.insert(tk.END, f" 📄 {f}") # ======================== # 11. 应用商店 # ======================== def open_store(self): wid, win, frame = self.new_window("📦 应用商店", 700, 500) tk.Label(frame, text="🏪 应用商店", font=self.font_title, fg="green").pack(pady=10) apps = ["Office Suite", "Photo Editor", "Music Player", "Game Pack"] for app in apps: btn = tk.Button(frame, text=f"⬇️ 安装 {app}", bg="white", font=self.font_ui) btn.pack(fill=tk.X, padx=20, pady=5) # ======================== # 12. AI 助手 # ======================== def open_ai_assistant(self): wid, win, frame = self.new_window("💬 AI 助手", 500, 400) chat = tk.Text(frame, bg="white", fg="black", font=self.font_code) chat.pack(fill=tk.BOTH, expand=True) msg = simpledialog.askstring("AI 助手", "向 AI 提问:") if msg: response = f"🤖 我是一个模拟 AI。\n你问的是:'{msg}'\n建议集成真实 LLM API。" chat.insert(tk.END, "👨‍💻: " + msg + "\n\n") chat.insert(tk.END, "🤖: " + response + "\n") # ======================== # 13. 电源管理 # ======================== def reboot_system(self): self.fade_out() self.root.after(600, self.do_reboot) def do_reboot(self): self.clear_root() self.boot_animation() self.root.after(3500, self.setup_desktop) def shutdown_system(self): self.fade_out() self.root.after(600, self.do_shutdown) def do_shutdown(self): off_win = tk.Toplevel(self.root) off_win.overrideredirect(True) off_win.geometry(f"{self.root.winfo_screenwidth()}x{self.root.winfo_screenheight()}+0+0") off_win.configure(bg="black") tk.Label(off_win, text="👋 系统已关闭。你可以安全地关闭计算机。", fg="white", bg="black", font=('Segoe UI', 16)).place(relx=0.5, rely=0.5, anchor=tk.CENTER) self.root.after(3000, self.root.quit) def fade_out(self): for i in range(100, 0, -5): self.root.attributes('-alpha', i / 100) self.root.update() time.sleep(0.03) def fade_in(self): for i in range(0, 101, 5): self.root.attributes('-alpha', i / 100) self.root.update() time.sleep(0.03) # ======================== # 14. 工具函数 # ======================== def clear_root(self): for widget in self.root.winfo_children(): widget.destroy() def add_notification(self, msg): timestamp = datetime.now().strftime("%H:%M") self.notification_log.append(f"[{timestamp}] {msg}") if len(self.notification_log) > 100: self.notification_log.pop(0) def show_notifications(self, event): win = tk.Toplevel(self.root) win.title("🔔 通知中心") win.geometry("400x300") win.configure(bg="white") lb = tk.Listbox(win, font=self.font_code, bg="white", fg="black") lb.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) for msg in reversed(self.notification_log[-20:]): lb.insert(0, msg) def copy_text(self, widget): try: selected = widget.get(tk.SEL_FIRST, tk.SEL_LAST) self.clipboard = selected except tk.TclError: pass def cut_text(self, widget): self.copy_text(widget) try: widget.delete(tk.SEL_FIRST, tk.SEL_LAST) except tk.TclError: pass def paste_text(self, widget): if self.clipboard: widget.insert(tk.INSERT, self.clipboard) if __name__ == "__main__": root = tk.Tk() app = Win12UltraVM(root) root.mainloop() 升级开、关、重启动画,完整版代码
最新发布
11-24
% FMCW雷达多目标仿真(优化最大不模糊速度) % 解决速度超过最大不模糊速度导致的模糊问题 clear; clc; close all; %% 雷达参数设置(优化最大不模糊速度) fc = 77e9; % 载频77GHz c = 3e8; % 光速 lambda = c/fc; % 波长 (~3.896mm) B = 500e6; % 调制带宽500MHz Tc = 50e-6; % 调制周期50μs(缩短周期提高最大不模糊速度) S = B/(Tc/2); % 扫频斜率 fs = 4e6; % 提高采样频率至4MHz N_up = round(fs*Tc/2); % 上升沿采样点数 N_down = N_up; % 下降沿采样点数 %% 目标设置 % 包含一个接近最大不模糊速度的目标 targets = [ 50, 10; % 目标1: 50m, 10m/s靠近 100, -5; % 目标2: 100m, 5m/s远离 150, 0 % 目标3: 150m, 静止 ]; numTargets = size(targets, 1); %% 生成拍频信号 t_up = 0:1/fs:(Tc/2 - 1/fs); % 上升沿时间 t_down = Tc/2:1/fs:(Tc - 1/fs); % 下降沿时间 beat_up = zeros(1, length(t_up)); beat_down = zeros(1, length(t_down)); for i = 1:numTargets R = targets(i, 1); v = targets(i, 2); % 多普勒频移 f_d = 2*v/lambda; % 上升沿拍频(考虑距离随时间变化) fb_up_i = (2*S*(R - v*t_up))/c + f_d; beat_up = beat_up + cos(2*pi*fb_up_i .* t_up); % 下降沿拍频 fb_down_i = (-2*S*(R - v*(t_down - Tc/2)))/c + f_d; beat_down = beat_down + cos(2*pi*fb_down_i .* (t_down - Tc/2)); end % 添加噪声 beat_up = awgn(beat_up, 15, ‘measured’); beat_down = awgn(beat_down, 15, ‘measured’); %% 信号处理 % 加窗FFT win = hamming(N_up); fft_up = fft(beat_up .* win, 2^nextpow2(N_up8)); fft_up = abs(fft_up(1:length(fft_up)/2)); fft_down = fft(beat_down . win, 2^nextpow2(N_down*8)); fft_down = abs(fft_down(1:length(fft_down)/2)); %% 计算参数 range_res = c/(2B); max_range = (c * Tc) / 2; vel_res = lambda/(4Tc); max_vel = lambda/(4*Tc); % 三角波调制最大不模糊速度 % 距离轴和速度轴 range_axis = (0:length(fft_up)-1)(cfs)/(4Slength(fft_up)); vel_axis = (-length(fft_up)/2:length(fft_up)/2-1)(lambdafs)/(4*N_up); %% 2D FFT获取距离-速度谱 beat_data = [beat_up; beat_down]; range_fft = fft(beat_data, [], 2); range_doppler = fftshift(fft(range_fft, [], 1), 1); range_doppler = abs(range_doppler); range_doppler = range_doppler / max(range_doppler(😃); %% 结果可视化 figure(‘Position’, [100 100 1400 900]); % 1. 拍频信号 subplot(2,2,1); plot(t_up1e6, beat_up, ‘b’, t_down1e6, beat_down, ‘r’); xlabel(‘时间 (μs)); ylabel(‘幅度’); title(‘上升沿()和下降沿()拍频信号’); grid on; legend(‘上升沿’, ‘下降沿’); % 2. 上升沿距离谱 subplot(2,2,2); plot(range_axis, fft_up/max(fft_up)); xlabel(‘距离 (m)); ylabel(‘归一化幅度’); title(‘上升沿距离谱’); xlim([0 max_range/5]); grid on; for i = 1:numTargets line([targets(i,1) targets(i,1)], [0 1], ‘Color’, ‘k’, ‘LineStyle’, ‘–’); end % 3. 下降沿距离谱 subplot(2,2,3); plot(range_axis, fft_down/max(fft_down)); xlabel(‘距离 (m)); ylabel(‘归一化幅度’); title(‘下降沿距离谱’); xlim([0 max_range/5]); grid on; for i = 1:numTargets line([targets(i,1) targets(i,1)], [0 1], ‘Color’, ‘k’, ‘LineStyle’, ‘–’); end % 4. 距离-速度谱 subplot(2,2,4); imagesc(range_axis, vel_axis, 20log10(range_doppler + eps)); colormap(‘jet’); colorbar; xlabel(‘距离 (m)); ylabel(‘速度 (m/s)); title(‘距离-速度谱(含虚像)’); xlim([0 max_range/5]); ylim([-max_vel1.2 max_vel*1.2]); hold on; for i = 1:numTargets plot(targets(i,1), targets(i,2), ‘wo’, ‘MarkerSize’, 10, ‘LineWidth’, 2); end annotation(‘textbox’, [0.05, 0.02, 0.2, 0.05], … ‘String’, ‘白色圆圈: 真实目标位置’, … ‘EdgeColor’, ‘none’, ‘BackgroundColor’, ‘w’); sgtitle(‘FMCW雷达多目标检测(优化最大不模糊速度)’); %% 参数输出 fprintf(===== 雷达系统参数 =====\n’); fprintf(‘载频: %.2f GHz\n’, fc/1e9); fprintf(‘调制带宽: %.2f MHz\n’, B/1e6); fprintf(‘调制周期: %.2f μs\n’, Tc*1e6); fprintf(‘距离分辨率: %.2f m\n’, range_res); fprintf(‘速度分辨率: %.4f m/s\n’, vel_res); fprintf(‘最大不模糊距离: %.2f m\n’, max_range); fprintf(‘最大不模糊速度: %.4f m/s\n’, max_vel); fprintf(‘\n===== 目标参数 =====\n’); fprintf(‘距离(m)\t速度(m/s)\n’); disp(targets); % 特别标注速度模糊情况 if any(abs(targets(:,2)) >= max_vel) fprintf(‘\n注意: 存在速度超过最大不模糊速度的目标,将产生速度模糊和虚像\n’); end 上升沿和下降沿距离谱峰值位置不对,二维谱无距离信息,速度为0,检查产生以上错误的原因并修改
09-18
我已经插入代码了啊% 多通道FMCW雷达系统仿真(高精度测距版) clear; close all; clc; %% 1. 系统参数设置(提升分辨率参数) fc = 77.0e9; % 载波频率 77 GHz B = 1.0e9; % 增大扫频带宽至1GHz(提升距离分辨率) T = 200.0e-6; % 扫频时间 200 μs Fs = 40.0e6; % 提高采样频率至40MHz c = 3e8; % 光速 num_channels = 3; % 接收通道数 num_chirps = 64; % 增加Chirp数至64(提升多普勒分辨率) lambda = c/fc; % 波长 % 性能参数计算 d_res = c/(2*B); % 距离分辨率(理论值) R_max = (c*T*Fs)/(2*B); % 最大不模糊距离 v_max = lambda/(4*T); % 最大不模糊速度 fprintf('=== 多通道FMCW雷达系统参数 ===\n'); fprintf('载波频率: %.1f GHz, 波长: %.3f mm\n', fc/1e9, lambda*1e3); fprintf('扫频带宽: %.1f GHz, 扫频时间: %.1f μs\n', B/1e9, T*1e6); fprintf('通道数: %d, 每帧Chirp数: %d, 采样频率: %.1f MHz\n', num_channels, num_chirps, Fs/1e6); fprintf('距离分辨率: %.3f m, 最大不模糊距离: %.1f m\n', d_res, R_max); fprintf('最大不模糊速度: %.1f m/s\n', v_max); %% 2. 目标参数设置(含无人机微多普勒) target_params = [ 60.0 5.2 1.2 0.05; % 距离(m)、速度(m/s)、RCS、微多普勒振幅(减小微动影响) 120.0 -3.8 0.8 0.04; 210.0 0.5 0.5 0.03 ]; num_targets = size(target_params, 1); % 多径参数(弱多径设置,减少干扰) multipath_params = [ 60.5 0.2; % 多径距离略偏离真实目标,RCS降低 120.6 0.1; 210.8 0.08 ]; num_multipaths = num_targets; % 打印目标信息 fprintf('\n=== 目标设置 ===\n'); for i = 1:num_targets fprintf('目标%d: 距离=%.1f m, 速度=%.1f m/s, RCS=%.1f\n', ... i, target_params(i,1), target_params(i,2), target_params(i,3)); end %% 3. 信号生成(多通道Chirp信号) t_chirp = 0:1/Fs:T-1/Fs; % 单Chirp时间向量 N = length(t_chirp); % 每Chirp采样点数 t_frame = 0:T:(num_chirps-1)*T; % 帧时间 % 发射信号(多通道,含相位偏移) slope = B/T; % 调频斜率 tx_signals = zeros(num_channels, N, num_chirps); for ch = 1:num_channels phase_offset = 2*pi*(ch-1)*0.05; % 减小通道相位差 for chirp = 1:num_chirps tx_signals(ch,:,chirp) = exp(1j*(2*pi*(fc*(t_chirp + t_frame(chirp)) + ... 0.5*slope*(t_chirp + t_frame(chirp)).^2) + phase_offset)); end end %% 4. 接收信号生成(含噪声优化) rx_signals = zeros(num_channels, N, num_chirps); for ch = 1:num_channels for chirp = 1:num_chirps rx_chirp = 0; t_current = t_chirp + t_frame(chirp); % 真实目标回波(元素级运算) for i = 1:num_targets R0 = target_params(i,1); v = target_params(i,2); rcs = target_params(i,3); v_micro = target_params(i,4); % 时变距离(含微动) R = R0 - v*t_current + v_micro*sin(2*pi*30*t_current); % 降低微动频率 % 衰减与多普勒(元素级运算) tau = 2*R/c; attenuation = rcs ./ (R .^ 2); % 修复矩阵运算错误 f_doppler = 2*(v - v_micro*30*2*pi*cos(2*pi*30*t_current))/lambda; rx_chirp = rx_chirp + attenuation .* exp(1j*(2*pi*(fc*(t_current - tau) + ... 0.5*slope*(t_current - tau).^2) + 2*pi*f_doppler.*t_current)); end % 多径回波 for i = 1:num_multipaths R_mp = multipath_params(i,1); rcs_mp = multipath_params(i,2); tau_mp = 2*R_mp/c; attenuation_mp = rcs_mp ./ (R_mp .^ 2); rx_chirp = rx_chirp + attenuation_mp .* exp(1j*(2*pi*(fc*(t_current - tau_mp) + ... 0.5*slope*(t_current - tau_mp).^2))); end rx_signals(ch,:,chirp) = rx_chirp; end end % 提高信噪比(减少噪声影响) SNR_dB = 25; % 信噪比提升至25dB rx_power = mean(abs(rx_signals(1,:,:)).^2, 'all'); noise_power = rx_power / (10^(SNR_dB/10)); for ch = 1:num_channels noise = sqrt(noise_power/2) * (randn(1, N, num_chirps) + 1j*randn(1, N, num_chirps)); rx_signals(ch,:,:) = rx_signals(ch,:,:) + noise; end %% 5. 高精度信号处理 % 5.1 通道均衡(自适应算法) eq_weights = ones(num_channels, 1); ref_ch = 1; for ch = 2:num_channels % 基于互相关的精确均衡 corr_vals = xcorr(abs(rx_signals(ref_ch,:,1)), abs(rx_signals(ch,:,1))); [~, max_idx] = max(corr_vals); delay = max_idx - length(rx_signals(ref_ch,:,1)); rx_shifted = circshift(rx_signals(ch,:,1), delay); % 补偿时延 eq_weights(ch) = mean(rx_signals(ref_ch,:,1) ./ rx_shifted); % 幅度相位补偿 rx_signals(ch,:,:) = rx_signals(ch,:,:) .* eq_weights(ch); end % 5.2 去斜处理 if_signals = zeros(num_channels, N, num_chirps); for ch = 1:num_channels for chirp = 1:num_chirps if_signals(ch,:,chirp) = tx_signals(ch,:,chirp) .* conj(rx_signals(ch,:,chirp)); end end % 5.3 距离FFT(明确维度,确保存储正确) range_fft_size = 2^nextpow2(16*N); % 大幅提高FFT点数 range_spectra = zeros(num_channels, range_fft_size, num_chirps); % 维度:[通道数 × range_fft_size × Chirp数] window = chebwin(N, 60); % 切比雪夫窗(更低旁瓣) for ch = 1:num_channels for chirp = 1:num_chirps if_windowed = if_signals(ch,:,chirp) .* window; % FFT后是长度为range_fft_size的一维数组,直接赋值到对应维度 range_spectra(ch,:,chirp) = fft(if_windowed, range_fft_size); end end % 5.4 多普勒FFT doppler_fft_size = 2^nextpow2(4*num_chirps); doppler_axis = (-doppler_fft_size/2 : doppler_fft_size/2-1) * (lambda/(4*T*doppler_fft_size)) * doppler_fft_size; rd_spectra = zeros(num_channels, range_fft_size, doppler_fft_size); for ch = 1:num_channels for r = 1:range_fft_size chirp_data = squeeze(range_spectra(ch,r,:)); % 提取距离门的Chirp序列 chirp_padded = [chirp_data, zeros(1, doppler_fft_size - num_chirps)]; % 补零 rd_spectra(ch,r,:) = fftshift(fft(chirp_padded, doppler_fft_size)); % 多普勒FFT end end % 5.5 多通道相干融合 rd_spectrum = sum(rd_spectra, 1); % 相干累加(提升信噪比) rd_spectrum = squeeze(rd_spectrum); rd_mag = abs(rd_spectrum); rd_dB = 20*log10(rd_mag + eps); % 5.6 多径抑制(CFAR算法) [n_rows, n_cols] = size(rd_dB); guard_cells = 3; train_cells = 10; cfar_threshold = zeros(n_rows, n_cols); for i = 1:n_rows for j = 1:n_cols % 训练单元选择 train_idx = [max(1,j-train_cells-guard_cells):max(1,j-guard_cells-1), ... min(n_cols,j+guard_cells+1):min(n_cols,j+train_cells+guard_cells)]; if ~isempty(train_idx) noise_level = mean(rd_dB(i,train_idx)); cfar_threshold(i,j) = noise_level + 12; % 12dB检测门限 end end end rd_dB(rd_dB < cfar_threshold) = -60; % 抑制噪声和弱多径 %% 6. 高精度目标检测与参数估计 % 6.1 峰值检测(三维峰值搜索) peaks = []; peak_locs = []; for i = 1:num_targets [max_val, max_idx] = max(rd_dB(:)); [r_idx, v_idx] = ind2sub(size(rd_dB), max_idx); peaks = [peaks; max_val]; peak_locs = [peak_locs; r_idx, v_idx]; rd_dB(r_idx-2:r_idx+2, v_idx-2:v_idx+2) = -60; % 标记后抑制,避免重复检测 end % 6.2 高斯拟合优化峰值位置(比抛物线插值更精确) detected_ranges = zeros(1, num_targets); detected_velocities = zeros(1, num_targets); for i = 1:num_targets r_idx = peak_locs(i,1); v_idx = peak_locs(i,2); % 提取峰值周围数据用于拟合 r_win = max(1, r_idx-2):min(length(range_axis), r_idx+2); v_win = max(1, v_idx-2):min(length(doppler_axis), v_idx+2); [R_grid, V_grid] = meshgrid(range_axis(r_win), doppler_axis(v_win)); Z = rd_dB(r_win, v_win); % 高斯拟合(最小二乘估计) X0 = [range_axis(r_idx); doppler_axis(v_idx); 1; peaks(i); -1]; % 初始值 model = @(p, x) p(4)*exp(-((x(:,1)-p(1))/p(3)).^2 - ((x(:,2)-p(2))/p(3)).^2); x_data = [R_grid(:), V_grid(:)]; y_data = Z(:); p_fit = lsqcurvefit(model, X0, x_data, y_data); detected_ranges(i) = p_fit(1); % 拟合后的距离 detected_velocities(i) = p_fit(2); % 拟合后的速度 end %% 7. 测距误差计算 true_ranges = target_params(:,1); range_errors = detected_ranges - true_ranges; % 测距误差 % 误差统计指标 mean_abs_error = mean(abs(range_errors)); % 平均绝对误差 rmse = sqrt(mean(range_errors.^2)); % 均方根误差 max_error = max(abs(range_errors)); % 最大误差 %% 8. 结果可视化 figure('Position', [100, 100, 1400, 1000]); % 8.1 距离-多普勒谱 subplot(2,2,1); imagesc(range_axis, doppler_axis, rd_dB'); colormap('jet'); colorbar; title('距离-多普勒谱(高精度处理后)'); xlabel('距离 (m)'); ylabel('速度 (m/s)'); xlim([0, 250]); ylim([-8, 8]); axis xy; hold on; plot(true_ranges, target_params(:,2), 'go', 'MarkerSize', 8, 'LineWidth', 2); plot(detected_ranges, detected_velocities, 'ro', 'MarkerSize', 6, 'LineWidth', 2); legend('真实目标', '检测目标'); hold off; % 8.2 测距误差条形图 subplot(2,2,2); bar(range_errors); title('各目标测距误差'); xlabel('目标序号'); ylabel('误差 (m)'); grid on; ylim([-0.05, 0.05]); xticks(1:num_targets); % 8.3 通道均衡效果 subplot(2,2,3); plot(range_axis, abs(range_spectra(1,:,1)), 'b-', 'LineWidth', 1.2); hold on; plot(range_axis, abs(range_spectra(2,:,1)), 'r--', 'LineWidth', 1.2); plot(range_axis, abs(range_spectra(2,:,1).*eq_weights(2)), 'g-', 'LineWidth', 1.2); title('通道均衡效果'); xlabel('距离 (m)'); ylabel('幅度'); legend('通道1', '通道2(均衡前)', '通道2(均衡后)'); xlim([0, 250]); grid on; % 8.4 目标1的距离谱细节 t1_range = true_ranges(1); t1_idx = find(range_axis >= t1_range-1 & range_axis <= t1_range+1); subplot(2,2,4); plot(range_axis(t1_idx), rd_dB(t1_idx, abs(doppler_axis - target_params(1,2)) < 0.2), 'b-', 'LineWidth', 1.5); hold on; plot(detected_ranges(1), max(rd_dB(t1_idx,:)), 'ro', 'MarkerSize', 8); plot(t1_range, max(rd_dB(t1_idx,:))-5, 'go', 'MarkerSize', 8); title('目标1距离谱细节'); xlabel('距离 (m)'); ylabel('幅度 (dB)'); legend('距离谱', '检测峰值', '真实位置'); grid on; %% 9. 结果输出 fprintf('\n=== 高精度测距结果 ===\n'); fprintf('%-8s %-12s %-12s %-12s\n', '目标', '真实距离(m)', '检测距离(m)', '测距误差(m)'); fprintf('------------------------------------------------\n'); for i = 1:num_targets fprintf('目标%-6d %-12.4f %-12.4f %-12.6f\n', ... i, true_ranges(i), detected_ranges(i), range_errors(i)); end fprintf('\n=== 误差统计 ===\n'); fprintf('平均绝对误差: %.6f m\n', mean_abs_error); fprintf('均方根误差(RMSE): %.6f m\n', rmse); fprintf('最大误差: %.6f m\n', max_error); fprintf('\n仿真完成!\n');
11-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值