_二級繼電器程控放大倍數自動設置

簡介

? ? ? ? 在開發項目中,有時會遇到需要使用程控放大的情況,如果沒有opa那種可編程放大器,那么就需要通過繼電器來控制放大倍數。而在繼電器程控中,常用的是二級程控,三級程控相較于二級就復雜了許多。

? ? ? ? 在二級程控中,每級繼電器都有兩種狀態,因此每級都可以設置兩個倍數,兩級級聯共4種放大倍數。對于具體應用場景來說,難的是如何設置合適的不同放大倍數劃分不同的子區間,使其可以對輸入區間的不同子區間進行選擇性放大,并且每個檔位都能合理覆蓋這些子區間,進而使得增益后的子區間均處于適合的范圍。

具體場景

? ? ? ? 舉個具體例子,現在ADC采集電壓峰峰值范圍為0~2V,而輸入的電壓為30mV到600mV。對于電壓30mV和600mV來說,放大倍數應分別接近66.7和3.3,那么就需要對其不同區間進行選擇性放大。那么這就設計到了如何選取區間,4個放大倍數自然需要把輸入區間劃分為4個連續子區間。放大之后還需要確保,增益的子區間應在ADC采集的范圍內。

? ? ? ? 也就是說,我們能獲得的信息是輸入的區間范圍(如30mV~600mV)和輸出的區間范圍(如0~2V),而我們需要的信息則是不同的放大倍數和劃分的子區間。在此例中,為了能及時察覺到放大倍數是否過大,那么應讓每個區間放大后的上限小于ADC的上限(2V),以便可以通過檢測ADC電壓是否大于子區間上限并接近上限電壓,進而及時調整程控倍數。下限亦是如此。

建模

? ? ? ? 根據具體的應用場景,可以很輕松地為其建模:

????????對于一個輸入電壓范圍x1,x2,可以把它分為4個連續區間范圍(左閉右開),而現在有一級放大倍數O1min和O1max,二級放大倍數O2min和O2max,這四個數可以排列組合得到不同的乘積a,b,c,d。那么如何找到四個乘積a、b、c、d(由一級放大倍數O1和二級放大倍數O2的組合產生),以及四個區間的分割點,使得每個分割后的區間內的x乘以對應的乘積后落在[Vmin, Vmax]內,并且分割后的四個區間連續覆蓋輸入范圍。

解決

? ? ? ? 進行建模后,并不好從數學角度快速解出4個放大倍數和4個連續子區間。但可以通過編程來遍歷所有合適的條件。如圖,這是個簡單的C++程序,可以向其指定輸入區間、輸出區間、步長和線程數。不過需要注意的是,找到的結果是對稱的,也就是說兩級放大倍數互換,在程序里是兩種情況,而非一種情況。

小工具的使用

簡介?

???????使用方法很簡單,與一般工具無異,通過指定參數來進行相應操作。此處,小工具的名稱為auto_OPA.exe

輸入區間?

???????以前面的例子而言,輸入區間為30mV到600mV,那么可以寫成下面形式(這里以mV為單位,也可以以V為單位,即-i 0.03 0.6。需要確保后面也使用相同單位)

.\auto_OPA.exe -i 30 600

輸出區間

????????各個子區間增益后的區間范圍

.\auto_OPA.exe -o 875 1900

步長

????????決定了放大倍數的最小分辨率

.\auto_OPA.exe -s 0.5

????????步長不建議選擇太小,比如0.1,其耗時遠遠高于步長為0.5用時的5倍,并且消耗內存會會大幅增加,因為找到的結果會先保存起來

????????另一方面,整數放大或者半整數放大在實際電路設計中較為常見,也比較好設計。

線程數

????????決定了程序運行快慢。由于程序里內嵌套了多個for循環,建議有多少核就用多少核,如果滿核的話,CPU占用率會達到100%,這很正常。

.\auto_OPA.exe -j 16

說明

參數也可以聯合指定,不區分先后順序

.\auto_OPA.exe -i 30 600 -o 875 1900 -s 0.5 -j 16

????????此外,程序還有默認值(就是任何參數都不指定的情況下),可自行到源碼里設置,然后編譯運行

????????其中放大倍數的上下限是根據輸入區間范圍和輸出區間范圍動態決定的,并不需要額外指定。

如果需要,那么可以顯示設定上下限

vector<double> generate_O_values(double x_min, double x_max, double Vmin, double Vmax, double step) {vector<double> values;double min_O = ceil((Vmin/x_max)/step)*step;  // 顯式下限double max_O = floor((Vmax/x_min)/step)*step;  // 精確上限for (double v = min_O; v <= max_O + 1e-9; v += step) {values.push_back(v);}return values;
}

運行結果

程序運行

保存的結果,其中O1為一級放大器的兩個放大倍數,O2位二級放大器的放大倍數

源代碼

gitcode:GitCode - 全球開發者的開源社區,開源代碼托管平臺

github:ichliebedich-DaCapo/auto_OPA

#include <iostream>
#include <vector>
#include <algorithm>
#include <thread>
#include <mutex>
#include <atomic>
#include <fstream>
#include <string>
#include <cmath>
#include <iomanip>
#include <getopt.h>using namespace std;// ANSI顏色代碼
#define BLUE    "\033[34m"
#define GREEN   "\033[32m"
#define RESET   "\033[0m"struct Result
{double O1min{}, O1max{}, O2min{}, O2max{};vector<double> gains;vector<double> split_points;
};vector<Result> global_results;
mutex results_mutex;
atomic<int> processed(0);
atomic<int> found_results(0);vector<double> generate_O_values(double x, double Vmax, double step)
{vector<double> values;double max_O = Vmax / x;for (double v = step; v <= max_O + 1e-9; v += step){values.push_back(v);}return values;
}void display_progress(int total, int found)
{const float progress = static_cast<float>(processed) / total;const int bar_width = 50;cout << BLUE << "\r[";const int pos = bar_width * progress;for (int i = 0; i < bar_width; ++i){if (i < pos) cout << "=";else if (i == pos) cout << ">";else cout << " ";}cout << "] " << static_cast<int>(progress * 100.0) << "%" << RESET;cout << " " << GREEN << "Found: " << found << RESET << flush;
}void display_thread_func(int total)
{while (processed < total){this_thread::sleep_for(chrono::milliseconds(100));int current_processed = processed.load();int current_found = found_results.load();display_progress(total, current_found);}display_progress(total, found_results.load());cout << endl;
}void worker(const vector<pair<int, int> > &O1_combs, const vector<pair<int, int> > &O2_combs,const vector<double> &O1_values, const vector<double> &O2_values,double x1, double x2, double Vmin, double Vmax, int total_O1_combs)
{while (true){int idx = processed.fetch_add(1);if (idx >= total_O1_combs) break;const auto &[fst, snd] = O1_combs[idx];const double O1min = O1_values[fst];const double O1max = O1_values[snd];for (auto &O2_pair: O2_combs){const double O2min = O2_values[O2_pair.first];const double O2max = O2_values[O2_pair.second];const double k1 = O1min * O2min;const double k2 = O1min * O2max;const double k3 = O1max * O2min;const double k4 = O1max * O2max;if (k1 == k2 || k1 == k3 || k1 == k4 || k2 == k3 || k2 == k4 || k3 == k4) continue;vector<double> gains = {k1, k2, k3, k4};ranges::sort(gains);do{if (gains[3] < Vmin / x2 - 1e-9 || gains[3] > Vmax / x2 + 1e-9) continue;if (gains[0] < Vmin / x1 - 1e-9) continue;double d0 = x1;double d1_low = max(d0, Vmin / gains[1]);double d1_high = Vmax / gains[0];if (d1_low > d1_high + 1e-9) continue;double d1 = d1_low;double d2_low = max(d1, Vmin / gains[2]);double d2_high = Vmax / gains[1];if (d2_low > d2_high + 1e-9) continue;double d2 = d2_low;const double d3_low = max(d2, Vmin / gains[3]);const double d3_high = min(Vmax / gains[2], x2);if (d3_low > d3_high + 1e-9) continue;double d3 = d3_low;if (d3 > x2 + 1e-9) continue;Result res;res.O1min = O1min;res.O1max = O1max;res.O2min = O2min;res.O2max = O2max;res.gains = gains;res.split_points = {d1, d2, d3};lock_guard<mutex> lock(results_mutex);global_results.push_back(res);found_results.fetch_add(1);} while (ranges::next_permutation(gains).found);}}
}int main(int argc, char *argv[])
{double x1 = 30, x2 = 600, Vmin = 875, Vmax = 1950, step = 0.5;int threads = 16;// 解析命令行參數int opt;while ((opt = getopt(argc, argv, "i:o:s:j:h")) != -1){switch (opt){case 'i':x1 = stod(optarg);x2 = stod(argv[optind++]);break;case 'o':Vmin = stod(optarg);Vmax = stod(argv[optind++]);break;case 's':step = stod(optarg);break;case 'j':threads = stoi(optarg);break;case 'h':// 中文會亂碼// cout << "[-i]:輸入區間范圍,比如-i 0.03 0.6\n"//         << "[-o]:輸出區間范圍,比如-o 0.9 2\n"//         << "[-s]:步長,比如-s 0.5\n"//         << "[-j]:線程數,比如-j 16\n"//         << "[-h]:幫助信息\n";;cout << "Two-Stage Programmable Amplifier Configuration Finder\n\n"<< "Usage:\n"<< "  ./auto_OPA -i <x_low> <x_high> -o <Vmin> <Vmax> [options]\n\n"<< "Required Parameters:\n"<< "  -i  Input voltage range (left-closed right-open interval)\n"<< "      Example: -i 0.03 0.6\n"<< "  -o  Desired output voltage range\n"<< "      Example: -o 1.0 3.3\n\n"<< "Options:\n"<< "  -s  Step size for gain search (default: 0.1)\n"<< "  -j  Number of parallel threads (default: CPU core count)\n"<< "  -h  Display this help message\n\n"<< "Validation Criteria:\n"<< "  1. Input coverage: [x_low, x_high] must be fully covered\n"<< "  2. Output constraint: ?x∈[x_low,x_high], Vmin ≤ x·gain ≤ Vmax\n"<< "  3. Gain continuity: Adjacent regions must have overlapping gains\n";exit(1);default:cerr << "Usage: " << argv[0]<< " -i x_low x_high -o Vmin Vmax -s step -j threads\n";exit(1);}}// 打印參數cout << "Vin  [" << x1 << "," << x2 << "]\nVout [" << Vmin << "," << Vmax << "]\nstep=" << step << "\nthreads=" <<threads << endl;auto O1_values = generate_O_values(x1, Vmax, step);auto O2_values = generate_O_values(x1, Vmax, step);vector<pair<int, int> > O1_combs;for (int i = 0; i < O1_values.size(); ++i)for (int j = i + 1; j < O1_values.size(); ++j)O1_combs.emplace_back(i, j);vector<pair<int, int> > O2_combs;for (int i = 0; i < O2_values.size(); ++i)for (int j = i + 1; j < O2_values.size(); ++j)O2_combs.emplace_back(i, j);int total_O1_combs = O1_combs.size();thread display_thread(display_thread_func, total_O1_combs);vector<thread> workers;for (int i = 0; i < threads; ++i)workers.emplace_back(worker, ref(O1_combs), ref(O2_combs), ref(O1_values),ref(O2_values), x1, x2, Vmin, Vmax, total_O1_combs);for (auto &t: workers) t.join();display_thread.join();ofstream out("results.txt");for (int i = 0; i < global_results.size(); ++i){auto &[O1min, O1max, O2min, O2max, gains, split_points] = global_results[i];out << "Result " << i + 1 << ":\n";out << fixed << setprecision(6);out << "O1: [" << O1min << ", " << O1max << "]\n";out << "O2: [" << O2min << ", " << O2max << "]\n";out << "Gains: ";for (auto g: gains) out << g << " ";out << "\nSplit Zone: ";// 子區間double zone[]={x1, split_points[0], split_points[1], split_points[2], x2};for (int n = 0; n < 4; ++n){out << "\n[" << zone[n] << "," << zone[n + 1] << "]\t\t"<<"[" << gains[n] * zone[n] << "," << gains[n]*zone[n + 1] << "]";}out << "\n\n";}return 0;
}

下載小工具

? ? ? ? 程序已上傳gitcode和github,可通過下面鏈接進行下載

Release詳情 - auto_OPA - GitCode

Release auto_OPA v1.0.0 · ichliebedich-DaCapo/auto_OPA

三級程控放大倍數(無)

? ? ? ? 依照相同的原理,三級也能實現,不過計算量實在太大,不建議編程來確定最佳區間。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/897339.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/897339.shtml
英文地址,請注明出處:http://en.pswp.cn/news/897339.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

電腦總顯示串口正在被占用處理方法

1.現象 在嵌入式開發過程中&#xff0c;有很多情況下要使用串口調試&#xff0c;其中485/422/232轉usb串口是非常常見的做法。 根據協議&#xff0c;接口芯片不同&#xff0c;需要安裝對應的驅動程序&#xff0c;比如ch340&#xff0c;cp2102&#xff0c;CDM212364等驅動。可…

優雅拼接字符串:StringJoiner 的完整指南

在Java開發中&#xff0c;字符串拼接是高頻操作。無論是日志格式化、構建CSV數據&#xff0c;還是生成動態SQL&#xff0c;開發者常需處理分隔符、前綴和后綴的組合。傳統的StringBuilder雖然靈活&#xff0c;但代碼冗余且易出錯。Java 8推出的StringJoiner類&#xff0c;以簡潔…

LabVIEW閉環控制系統硬件選型與實時性能

在LabVIEW閉環控制系統的開發中&#xff0c;硬件選型直接影響系統的實時性、精度與穩定性。需綜合考慮數據采集速度&#xff08;采樣率、接口帶寬&#xff09;、計算延遲&#xff08;算法復雜度、處理器性能&#xff09;、輸出響應時間&#xff08;執行器延遲、控制周期&#x…

Hive的架構

1. 概念 Hive 是建立在 Hadoop 上的數據倉庫工具&#xff0c;旨在簡化大規模數據集的查詢與管理。它通過類 SQL 語言&#xff08;HiveQL&#xff09;將結構化數據映射為 Hadoop 的 MapReduce&#xff0c;適合離線批處理&#xff0c;尤其適用于數據倉庫場景。 2. 數據模型 表&a…

深入解析:Linux中KVM虛擬化技術

這篇文章將深入分析Linux中虛擬化技術的實現----KVM技術&#xff0c;從KVM技術的簡介、技術架構、以及虛擬機和宿主機交互的重要處理邏輯出發&#xff0c;深入探究KVM技術的實現。 一、KVM簡介&#xff1a; 首先&#xff0c;我們先查看一下KVM架構&#xff0c;看看它的整體工…

golang學習筆記——go語言安裝及系統環境變量設置

文章目錄 go語言安裝go envgo getgoproxy測試安裝 Go 插件安裝 Go 插件依賴工具參考資料用戶環境變量和系統環境變量用戶環境變量系統環境變量示例設置環境變量的步驟設置用戶環境變量設置系統環境變量 驗證環境變量總結 2024年最火的5大Go框架1. Gin&#xff1a;高并發接口的“…

3.6c語言

#define _CRT_SECURE_NO_WARNINGS #include <math.h> #include <stdio.h> int main() {int sum 0,i,j;for (j 1; j < 1000; j){sum 0;for (i 1; i < j; i){if (j % i 0){sum i;} }if (sum j){printf("%d是完數\n", j);}}return 0; }#de…

【TI】如何更改 CCS20.1.0 的 WORKSPACE 默認路徑

參考鏈接&#xff1a; 如何更改 CCS Theia 中工作區的默認位置&#xff1f;- Code Composer Studio 論壇 - Code Composer Studio?? - TI E2E 支持論壇 --- How to change the default location for the workspace in CCS Theia? - Code Composer Studio forum - Code Comp…

Vue3中動態Ref的魔法:綁定與妙用

前言 在Vue 3的開發過程中,動態綁定Ref是一項非常實用的技術,特別是在處理復雜組件結構和動態數據時。通過動態綁定Ref,我們可以更靈活地訪問和操作DOM元素或組件實例,實現更高效的交互和狀態管理。本文將詳細介紹如何在Vue 3中實現動態Ref的綁定,并通過實例展示其妙用。…

CarPlanner:用于自動駕駛大規模強化學習的一致性自回歸軌跡規劃

25年2月來自浙大和菜鳥網絡的論文“CarPlanner: Consistent Auto-regressive Trajectory Planning for Large-scale Reinforcement Learning in Autonomous Driving”。 軌跡規劃對于自動駕駛至關重要&#xff0c;可確保在復雜環境中安全高效地導航。雖然最近基于學習的方法&a…

VS Code連接服務器教程

VS Code是什么 VS Code&#xff08;全稱 Visual Studio Code&#xff09;是一款由微軟推出的免費、開源、跨平臺的代碼編輯神器。VS Code 支持 所有主流操作系統&#xff0c;擁有強大的功能和靈活的擴展性。 官網&#xff1a;https://code.visualstudio.com/插件市場&#xff1…

【JavaWeb】Web基礎概念

文章目錄 1、服務器與客戶端2、服務器端應用程序3、請求和響應4、項目的邏輯構成5、架構5.1 概念5.2 發展演變歷程單一架構分布式架構 5.3 單一架構技術體系 6、本階段技術體系 1、服務器與客戶端 ①線下的服務器與客戶端 ②線上的服務器與客戶端 2、服務器端應用程序 我…

安徽省考計算機專業科目2025(持續更新)

目錄 第一部分 計算機科學技術基礎 第一章 計算機及其應用基礎知識 1.1 計算機的特點、分類及其應用 1.2 信息編碼與數據表示&#xff1b;數制及其轉換方法&#xff1b;算術運算和邏輯運算的過程 第一部分 計算機科學技術基礎 第一章 計算機及其應用基礎知識 1.1 計算機…

前端知識點---路由模式-實例模式和單例模式(ts)

在 ArkTS&#xff08;Ark UI 框架&#xff09;中&#xff0c;路由實例模式&#xff08;Standard Instance Mode&#xff09;主要用于管理頁面跳轉。當創建一個新頁面時&#xff0c;可以選擇標準實例模式&#xff08;Standard Mode&#xff09;或單實例模式&#xff08;Single M…

【leetcode hot 100 73】矩陣置零

解法一&#xff1a;&#xff08;使用兩個標記變量&#xff09;用矩陣的第一行和第一列代替方法一中的兩個標記數組&#xff08;col、row[ ]&#xff1a;第幾列、行出現0&#xff09;&#xff0c;以達到 O(1) 的額外空間。 這樣會導致原數組的第一行和第一列被修改&#xff0c;…

【十三】Golang 通道

&#x1f4a2;歡迎來到張胤塵的開源技術站 &#x1f4a5;開源如江河&#xff0c;匯聚眾志成。代碼似星辰&#xff0c;照亮行征程。開源精神長&#xff0c;傳承永不忘。攜手共前行&#xff0c;未來更輝煌&#x1f4a5; 文章目錄 通道通道聲明初始化緩沖機制無緩沖通道代碼示例 帶…

【JAVA架構師成長之路】【電商系統實戰】第12集:秒殺系統性能優化實戰(CAN + Nginx + Sentinel)

30分鐘課程&#xff1a;秒殺系統性能優化實戰&#xff08;CDN Nginx Sentinel&#xff09; 課程目標 掌握靜態資源 CDN 加速的配置與優化策略。通過 Nginx 實現負載均衡&#xff0c;提升系統橫向擴展能力。使用 Sentinel 實現服務降級&#xff0c;保障核心鏈路穩定性。 課程…

K8S學習之基礎十八:k8s的灰度發布和金絲雀部署

灰度發布 逐步擴大新版本的發布范圍&#xff0c;從少量用戶逐步擴展到全體用戶。 特點是分階段發布、持續監控、逐步擴展 適合需要逐步驗證和降低風險的更新 金絲雀部署 將新版本先部署到一小部分用戶或服務器&#xff0c;觀察其表現&#xff0c;再決定是否全面推廣。 特點&…

畢業項目推薦:基于yolov8/yolo11的蘋果葉片病害檢測識別系統(python+卷積神經網絡)

文章目錄 概要一、整體資源介紹技術要點功能展示&#xff1a;功能1 支持單張圖片識別功能2 支持遍歷文件夾識別功能3 支持識別視頻文件功能4 支持攝像頭識別功能5 支持結果文件導出&#xff08;xls格式&#xff09;功能6 支持切換檢測到的目標查看 二、數據集三、算法介紹1. YO…

redis有哪幾種持久化方式

Redis 提供了兩種持久化方式&#xff1a;RDB&#xff08;Redis Database&#xff09; 和 AOF&#xff08;Append-Only File&#xff09;。它們各有優缺點&#xff0c;適用于不同的場景。以下是它們的原理、優缺點以及如何選擇的建議&#xff1a; 1. RDB&#xff08;Redis Datab…