新的转换算法测试,更好的声音适配

This commit is contained in:
EillesWan 2024-01-08 00:08:52 +08:00
parent 0b0328bc44
commit fc138f1dbf
10 changed files with 215 additions and 385 deletions

View File

@ -17,8 +17,8 @@ Terms & Conditions: License.md in the root directory
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md # 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
__version__ = "1.6.1" __version__ = "1.6.2"
__vername__ = "更新乐器对照表" __vername__ = "新的转换算法测试,更好的声音适配"
__author__ = ( __author__ = (
("金羿", "Eilles Wan"), ("金羿", "Eilles Wan"),
("诸葛亮与八卦阵", "bgArray"), ("诸葛亮与八卦阵", "bgArray"),

View File

@ -25,6 +25,7 @@ from .subclass import *
from .utils import * from .utils import *
from .types import Tuple, List, Dict from .types import Tuple, List, Dict
class FutureMidiConvertRSNB(MidiConvert): class FutureMidiConvertRSNB(MidiConvert):
""" """
加入红石音乐适配 加入红石音乐适配
@ -57,101 +58,6 @@ class FutureMidiConvertRSNB(MidiConvert):
except KeyError: except KeyError:
return "air" return "air"
def to_note_list_in_delay(
self,
) -> Tuple[Dict[int, SingleNoteBox], int]:
"""
使用金羿的转换思路将midi转换为我的世界音符盒音高乐器及延迟列表并输出每个音符之后的延迟
Returns
-------
tuple( Dict[int, SingleNoteBox], int音乐时长游戏刻 )
"""
self.to_music_channels()
tracks = {}
note_range = {}
InstID = -1
# cmd_amount = 0
# 此处 我们把通道视为音轨
for i in self.channels.keys():
# 如果当前通道为空 则跳过
if not self.channels[i]:
continue
# 第十通道是打击乐通道
SpecialBits = True if i == 9 else False
for track_no, track in self.channels[i].items():
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
# block_id = self.soundID_to_block((
# self.perc_inst_to_soundID_withX(msg[1])
# if SpecialBits
# else self.inst_to_souldID_withX(InstID)
# )[0])
# delaytime_now = round(msg[-1] / 50)
note_ = 2 ** ((msg[1] - 60) / 12)
try:
tracks[msg[-1]].append(
(
InstID,
note_,
)
)
except KeyError:
tracks[msg[-1]] = [(InstID, note_)]
try:
note_range[InstID]["max"] = max(
note_range[InstID]["max"], note_
)
note_range[InstID]["min"] = min(
note_range[InstID]["min"], note_
)
except KeyError:
note_range[InstID] = {"max": note_, "min": note_}
del InstID
all_ticks = list(tracks.keys())
all_ticks.sort()
results = []
print(note_range)
exit()
for i in range(len(all_ticks)):
for j in range(len(tracks[all_ticks[i]])):
results.append(
SingleCommand(
tracks[all_ticks[i]][j],
tick_delay=(
0
if j != 0
else (
all_ticks[i] - all_ticks[i - 1]
if i != 0
else all_ticks[i]
)
),
annotation="{}播放{}%{}".format(
mctick2timestr(i), max_volume * 100, ""
),
)
)
self.music_command_list = results
self.music_tick_num = max(all_ticks)
return results, self.music_tick_num
class FutureMidiConvertM4(MidiConvert): class FutureMidiConvertM4(MidiConvert):
""" """
@ -163,172 +69,50 @@ class FutureMidiConvertM4(MidiConvert):
@staticmethod @staticmethod
def _linear_note( def _linear_note(
_note: SingleNote, _note: SingleNote,
_apply_time_division: int = 100, _apply_time_division: float = 100,
) -> List[Tuple[int, int, int, int, float],]: ) -> List[SingleNote]:
"""传入音符数据,返回以半秒为分割的插值列表 """传入音符数据,返回以半秒为分割的插值列表
:param _note: SingleNote 音符 :param _note: SingleNote 音符
:param _apply_time_division: int 间隔毫秒数
:return list[tuple(int开始时间毫秒, int乐器, int音符, int力度内置, float音量播放),]""" :return list[tuple(int开始时间毫秒, int乐器, int音符, int力度内置, float音量播放),]"""
if _note.percussive:
return [
_note,
]
totalCount = int(_note.duration / _apply_time_division) totalCount = int(_note.duration / _apply_time_division)
if totalCount == 0: if totalCount == 0:
return [ return [
(_note.start_time, _note.inst, _note.pitch, _note.velocity, 1), _note,
] ]
# print(totalCount) # print(totalCount)
result: List[Tuple[int, int, int, int, float],] = [] result: List[SingleNote] = []
for _i in range(totalCount): for _i in range(totalCount):
result.append( result.append(
( SingleNote(
_note.start_time + _i * _apply_time_division, instrument=_note.inst,
_note.instrument, pitch=_note.pitch,
_note.pitch, velocity=_note.velocity,
_note.velocity, startime=int(_note.start_time + _i * (_note.duration / totalCount)),
((totalCount - _i) / totalCount), lastime=int(_note.duration / totalCount),
track_number=_note.track_no,
is_percussion=_note.percussive,
) )
# (
# _note.start_time + _i * _apply_time_division,
# _note.instrument,
# _note.pitch,
# _note.velocity,
# ((totalCount - _i) / totalCount),
# )
) )
return result return result
# 简单的单音填充
def to_command_list_in_score(
self,
scoreboard_name: str = "mscplay",
max_volume: float = 1.0,
speed: float = 1.0,
) -> Tuple[List[List[SingleCommand]], int, int]:
"""
使用金羿的转换思路使用完全填充算法优化音感后将midi转换为我的世界命令列表
Parameters
----------
scoreboard_name: str
我的世界的计分板名称
max_volume: float
最大播放音量注意这里的音量范围为(0,1]如果超出将被处理为正确值其原理为在距离玩家 (1 / volume -1) 的地方播放
speed: float
速度注意这里的速度指的是播放倍率其原理为在播放音频的时候每个音符的播放时间除以 speed
Returns
-------
tuple( list[list[SingleCommand指令,... ],... ], int指令数量, int音乐时长游戏刻 )
"""
if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数")
max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
self.to_music_channels()
note_channels: Dict[int, List[SingleNote]] = empty_midi_channels(staff=[])
InstID = -1
# 此处 我们把通道视为音轨
for i in self.channels.keys():
# 如果当前通道为空 则跳过
if not self.channels[i]:
continue
# nowChannel = []
for track_no, track in self.channels[i].items():
noteMsgs = []
MsgIndex = []
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
noteMsgs.append(msg[1:])
MsgIndex.append(msg[1])
elif msg[0] == "NoteE":
if msg[1] in MsgIndex:
note_channels[i].append(
SingleNote(
InstID,
msg[1],
noteMsgs[MsgIndex.index(msg[1])][1],
noteMsgs[MsgIndex.index(msg[1])][2],
msg[-1] - noteMsgs[MsgIndex.index(msg[1])][2],
track_number=track_no,
)
)
noteMsgs.pop(MsgIndex.index(msg[1]))
MsgIndex.pop(MsgIndex.index(msg[1]))
del InstID
tracks = []
cmd_amount = 0
max_score = 0
# 此处 我们把通道视为音轨
for no, track in note_channels.items():
# 如果当前通道为空 则跳过
if not track:
continue
SpecialBits = True if no == 9 else False
track_now = []
for note in track:
for every_note in self._linear_note(
note, 100 if note.track_no == 0 else 500
):
soundID, _X = (
self.perc_inst_to_soundID_withX(note.pitch)
if SpecialBits
else self.inst_to_souldID_withX(note.inst)
)
score_now = round(every_note[0] / speed / 50)
max_score = max(max_score, score_now)
mc_pitch = 2 ** ((note.pitch - 60 - _X) / 12)
blockmeter = (
1
/ (1 if note.track_no == 0 else 0.9)
/ max_volume
/ every_note[4]
- 1
)
track_now.append(
SingleCommand(
self.execute_cmd_head.format(
"@a[scores=({}={})]".format(scoreboard_name, score_now)
.replace("(", r"{")
.replace(")", r"}")
)
+ "playsound {} @s ^ ^ ^{} {} {}".format(
soundID,
blockmeter,
note.velocity / 128,
"" if SpecialBits else mc_pitch,
),
annotation="{}播放{}%({}BM)的{}".format(
mctick2timestr(score_now),
max_volume * 100,
blockmeter,
"{}:{}".format(soundID, note.pitch),
),
),
)
cmd_amount += 1
if track_now:
self.music_command_list.extend(track_now)
tracks.append(track_now)
self.music_tick_num = max_score
return (tracks, cmd_amount, max_score)
# 简单的单音填充的延迟应用
def to_command_list_in_delay( def to_command_list_in_delay(
self, self,
max_volume: float = 1.0, max_volume: float = 1.0,
@ -336,7 +120,7 @@ class FutureMidiConvertM4(MidiConvert):
player_selector: str = "@a", player_selector: str = "@a",
) -> Tuple[List[SingleCommand], int, int]: ) -> Tuple[List[SingleCommand], int, int]:
""" """
使用金羿的转换思路使用完全填充算法优化音感后将midi转换为我的世界命令列表并输出每个音符之后的延迟 将midi转换为我的世界命令列表并输出每个音符之后的延迟
Parameters Parameters
---------- ----------
@ -353,130 +137,48 @@ class FutureMidiConvertM4(MidiConvert):
""" """
if speed == 0: if speed == 0:
raise ZeroSpeedError("播放速度仅可为正实数") raise ZeroSpeedError("播放速度仅可为(0,1]范围内的正实数")
max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume) max_volume = 1 if max_volume > 1 else (0.001 if max_volume <= 0 else max_volume)
self.to_music_channels() notes_list: List[SingleNote] = []
note_channels: Dict[int, List[SingleNote]] = empty_midi_channels(staff=[])
InstID = -1
# 此处 我们把通道视为音轨 # 此处 我们把通道视为音轨
for i in self.channels.keys(): for channel in self.to_music_note_channels().values():
# 如果当前通道为空 则跳过 for note in channel:
if not self.channels[i]: if not note.percussive:
continue notes_list.extend(self._linear_note(note, note.get_mc_pitch * 500))
# nowChannel = []
for track_no, track in self.channels[i].items():
noteMsgs = []
MsgIndex = []
for msg in track:
if msg[0] == "PgmC":
InstID = msg[1]
elif msg[0] == "NoteS":
noteMsgs.append(msg[1:])
MsgIndex.append(msg[1])
elif msg[0] == "NoteE":
if msg[1] in MsgIndex:
note_channels[i].append(
SingleNote(
InstID,
msg[1],
noteMsgs[MsgIndex.index(msg[1])][1],
noteMsgs[MsgIndex.index(msg[1])][2],
msg[-1] - noteMsgs[MsgIndex.index(msg[1])][2],
track_number=track_no,
)
)
noteMsgs.pop(MsgIndex.index(msg[1]))
MsgIndex.pop(MsgIndex.index(msg[1]))
del InstID
tracks = {}
InstID = -1
# open("RES.TXT", "w", encoding="utf-8").write(str(note_channels))
# 此处 我们把通道视为音轨
for no, track in note_channels.items():
# 如果当前通道为空 则跳过
if not track:
continue
SpecialBits = True if no == 9 else False
for note in track:
liner_list = self._linear_note(note, 100 if note.track_no == 0 else 500)
for every_note in liner_list:
soundID, _X = (
self.perc_inst_to_soundID_withX(note.pitch)
if SpecialBits
else self.inst_to_souldID_withX(note.inst)
)
score_now = round(every_note[0] / speed / 50)
try:
tracks[score_now].append(
self.execute_cmd_head.format(player_selector)
+ f"playsound {soundID} @s ^ ^ ^{1 / (1 if note.track_no == 0 else 0.9) / max_volume / every_note[4] - 1} {note.velocity / 128} "
+ (
""
if SpecialBits
else f"{2 ** ((note.pitch - 60 - _X) / 12)}"
)
)
except KeyError:
tracks[score_now] = [
self.execute_cmd_head.format(player_selector)
+ f"playsound {soundID} @s ^ ^ ^{1 / (1 if note.track_no == 0 else 0.9) / max_volume / every_note[4] - 1} {note.velocity / 128} "
+ (
""
if SpecialBits
else f"{2 ** ((note.pitch - 60 - _X) / 12)}"
)
]
all_ticks = list(tracks.keys())
all_ticks.sort()
results: List[SingleCommand] = []
max_multi = 0
now_multi_delay = 0
now_multi = 0
for i in range(len(all_ticks)):
l = len(tracks[all_ticks[i]])
for j in range(l):
results.append(
SingleCommand(
tracks[all_ticks[i]][j],
tick_delay=(
0
if j != 0
else (
all_ticks[i] - all_ticks[i - 1]
if i != 0
else all_ticks[i]
)
),
annotation="由 音·创 生成",
)
)
if results[-1].delay + now_multi_delay <= 1:
now_multi += 1
now_multi_delay += results[-1].delay
else: else:
max_multi = max(max_multi, now_multi) notes_list.append(note)
now_multi = 0
now_multi_delay = 0
self.music_command_list = results notes_list.sort(key=lambda a: a.start_time)
self.music_tick_num = max(all_ticks)
return results, self.music_tick_num, max_multi self.music_command_list = []
multi = max_multi = 0
delaytime_previous = 0
for note in notes_list:
delaytime_now = round(note.start_time / speed / 50)
if (tickdelay := (delaytime_now - delaytime_previous)) == 0:
multi += 1
else:
max_multi = max(max_multi, multi)
multi = 0
self.music_command_list.append(
SingleCommand(
self.execute_cmd_head.format(player_selector)
+ note.to_command(max_volume),
tick_delay=tickdelay,
annotation="{}播放{}%{}".format(
mctick2timestr(delaytime_now),
max_volume * 100,
"{}:{}".format(note.mc_sound_ID, note.mc_pitch),
),
)
)
delaytime_previous = delaytime_now
self.music_tick_num = round(notes_list[-1].start_time / speed / 50)
return self.music_command_list, self.music_tick_num, max_multi + 1
class FutureMidiConvertM5(MidiConvert): class FutureMidiConvertM5(MidiConvert):

View File

@ -631,7 +631,9 @@ class MidiConvert:
.replace("(", r"{") .replace("(", r"{")
.replace(")", r"}") .replace(")", r"}")
) )
+ note.to_command(max_volume), + note.to_command(
(max_volume) if note.track_no == 0 else (max_volume * 0.9)
),
annotation="{}播放{}%{}".format( annotation="{}播放{}%{}".format(
mctick2timestr(score_now), mctick2timestr(score_now),
max_volume * 100, max_volume * 100,
@ -698,7 +700,9 @@ class MidiConvert:
self.music_command_list.append( self.music_command_list.append(
SingleCommand( SingleCommand(
self.execute_cmd_head.format(player_selector) self.execute_cmd_head.format(player_selector)
+ note.to_command(max_volume), + note.to_command(
(max_volume) if note.track_no == 0 else (max_volume * 0.9)
),
tick_delay=tickdelay, tick_delay=tickdelay,
annotation="{}播放{}%{}".format( annotation="{}播放{}%{}".format(
mctick2timestr(delaytime_now), mctick2timestr(delaytime_now),

View File

@ -21,7 +21,7 @@ from dataclasses import dataclass
from typing import Optional from typing import Optional
from .constants import PERCUSSION_INSTRUMENT_LIST from .constants import PERCUSSION_INSTRUMENT_LIST
from .utils import inst_to_souldID_withX, perc_inst_to_soundID_withX from .utils import inst_to_souldID_withX, perc_inst_to_soundID_withX, volume2distance
@dataclass(init=False) @dataclass(init=False)
@ -78,8 +78,6 @@ class SingleNote:
"""音符持续时间 ms""" """音符持续时间 ms"""
self.track_no: int = track_number self.track_no: int = track_number
"""音符所处的音轨""" """音符所处的音轨"""
self.track_no: int = track_number
"""音符所处的音轨"""
self.percussive = ( self.percussive = (
(is_percussion in PERCUSSION_INSTRUMENT_LIST) (is_percussion in PERCUSSION_INSTRUMENT_LIST)
@ -89,31 +87,48 @@ class SingleNote:
"""是否为打击乐器""" """是否为打击乐器"""
@property @property
def inst(self): def inst(self) -> int:
"""乐器编号""" """乐器编号"""
return self.instrument return self.instrument
@inst.setter @inst.setter
def inst(self, inst_): def inst(self, inst_: int):
self.instrument = inst_ self.instrument = inst_
@property @property
def pitch(self): def pitch(self) -> int:
"""音符编号""" """音符编号"""
return self.note return self.note
def __str__(self): @property
return "{}Note(Instrument = {}, {}Velocity = {}, StartTime = {}, Duration = {},)".format( def get_mc_pitch(self) -> float:
self.mc_sound_ID, _X = (
perc_inst_to_soundID_withX(self.inst)
if self.percussive
else inst_to_souldID_withX(self.inst)
)
return -1 if self.percussive else 2 ** ((self.note - 60 - _X) / 12)
def __str__(self, is_track: bool = False):
return "{}Note(Instrument = {}, {}Velocity = {}, StartTime = {}, Duration = {}{})".format(
"Percussive" if self.percussive else "", "Percussive" if self.percussive else "",
self.inst, self.inst,
"" if self.percussive else "Pitch = {}, ".format(self.pitch), "" if self.percussive else "Pitch = {}, ".format(self.pitch),
self.start_time, self.start_time,
self.duration, self.duration,
", Track = {}".format(self.track_no) if is_track else "",
) )
def __tuple__(self): def __tuple__(self):
return ( return (
(self.percussive, self.inst, self.velocity, self.start_time, self.duration) (
self.percussive,
self.inst,
self.velocity,
self.start_time,
self.duration,
self.track_no,
)
if self.percussive if self.percussive
else ( else (
self.percussive, self.percussive,
@ -122,6 +137,7 @@ class SingleNote:
self.velocity, self.velocity,
self.start_time, self.start_time,
self.duration, self.duration,
self.track_no,
) )
) )
@ -133,6 +149,7 @@ class SingleNote:
"Velocity": self.velocity, "Velocity": self.velocity,
"StartTime": self.start_time, "StartTime": self.start_time,
"Duration": self.duration, "Duration": self.duration,
"Track": self.track_no,
} }
if self.percussive if self.percussive
else { else {
@ -142,6 +159,7 @@ class SingleNote:
"Velocity": self.velocity, "Velocity": self.velocity,
"StartTime": self.start_time, "StartTime": self.start_time,
"Duration": self.duration, "Duration": self.duration,
"Track": self.track_no,
} }
) )
@ -165,14 +183,13 @@ class SingleNote:
# delaytime_now = round(self.start_time / float(speed) / 50) # delaytime_now = round(self.start_time / float(speed) / 50)
self.mc_pitch = "" if self.percussive else 2 ** ((self.note - 60 - _X) / 12) self.mc_pitch = "" if self.percussive else 2 ** ((self.note - 60 - _X) / 12)
self.mc_distance_volume = 128 / volume_percentage / self.velocity + (
1 if self.percussive else self.velocity / 32 self.mc_distance_volume = volume2distance(self.velocity * volume_percentage)
)
return "playsound {} @s ^ ^ ^{} {} {}".format( return "playsound {} @s ^ ^ ^{} {} {}".format(
self.mc_sound_ID, self.mc_sound_ID,
self.mc_distance_volume, self.mc_distance_volume,
self.velocity / 128, volume_percentage,
self.mc_pitch, self.mc_pitch,
) )

View File

@ -58,7 +58,7 @@ ChannelType = Dict[
], ],
] ]
""" """
以字典所标记的频道信息类型即将弃用 以字典所标记的频道信息类型弃用
Dict[int,Dict[int,List[Union[Tuple[Literal["PgmC"], int, int],Tuple[Literal["NoteS"], int, int, int],Tuple[Literal["NoteE"], int, int],]],],] Dict[int,Dict[int,List[Union[Tuple[Literal["PgmC"], int, int],Tuple[Literal["NoteS"], int, int, int],Tuple[Literal["NoteE"], int, int],]],],]
""" """

View File

@ -15,6 +15,8 @@ Terms & Conditions: License.md in the root directory
# Email TriM-Organization@hotmail.com # Email TriM-Organization@hotmail.com
# 若需转载或借鉴 许可声明请查看仓库目录下的 License.md # 若需转载或借鉴 许可声明请查看仓库目录下的 License.md
import math
from .constants import PERCUSSION_INSTRUMENT_TABLE, PITCHED_INSTRUMENT_TABLE from .constants import PERCUSSION_INSTRUMENT_TABLE, PITCHED_INSTRUMENT_TABLE
from typing import Any, Dict, Tuple from typing import Any, Dict, Tuple
@ -89,3 +91,29 @@ def perc_inst_to_soundID_withX(instrumentID: int) -> Tuple[str, int]:
# 明明已经走了 # 明明已经走了
# 凭什么还要在我心里留下缠绵缱绻 # 凭什么还要在我心里留下缠绵缱绻
def volume2distance(vol: float) -> float:
"""
midi力度值拟合成的距离函数
Parameters
----------
vol: int
midi音符力度值
Returns
-------
float播放中心到玩家的距离
"""
return (
-8.081720684086314
* math.log(
vol + 14.579508825070013,
)
+ 37.65806375944386
if vol < 60.64
else 0.2721359356095803 * ((vol + 2592.272889454798) ** 1.358571233418649)
+ -6.313841334963396 * (vol + 2592.272889454798)
+ 4558.496367823575
)

View File

@ -1,13 +1,13 @@
import Musicreater.experiment import Musicreater.experiment
import Musicreater.plugin import Musicreater.plugin
import Musicreater.plugin.addonpack import Musicreater.plugin.mcstructfile
print( print(
Musicreater.plugin.addonpack.to_addon_pack_in_delay( Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
Musicreater.experiment.FutureMidiConvertM4.from_midi_file(input("midi路径:"), old_exe_format=False), Musicreater.experiment.FutureMidiConvertM4.from_midi_file(
Musicreater.plugin.ConvertConfig( input("midi路径:"), old_exe_format=False
input("输出路径:"),
volume=1
), ),
Musicreater.plugin.ConvertConfig(input("输出路径:"), volume=1),
max_height=32,
) )
) )

View File

@ -6,5 +6,6 @@ print(
Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay( Musicreater.plugin.mcstructfile.to_mcstructure_file_in_delay(
Musicreater.MidiConvert.from_midi_file(input("midi路径:"), old_exe_format=False), Musicreater.MidiConvert.from_midi_file(input("midi路径:"), old_exe_format=False),
Musicreater.plugin.ConvertConfig(input("输出路径:"), volume=1), Musicreater.plugin.ConvertConfig(input("输出路径:"), volume=1),
max_height=32,
) )
) )

View File

@ -0,0 +1,42 @@
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
def q_function1(x, a, a2, c1,):
return a * np.log( x + a2,)+ c1
def q_function2(x, b, b2, b3, b4, c2):
return b * ((x + b2) ** b3) + b4 * (x+b2) + c2
x_data = np.array([0, 16, 32, 48, 64, 80, 96, 112, 128])
y_data = np.array([16, 10, 6.75, 4, 2.5, 1.6, 0.8, 0.3, 0])
p_est1, err_est1 = curve_fit(q_function1, x_data[:5], y_data[:5], maxfev=1000000)
p_est2, err_est2 = curve_fit(q_function2, x_data[4:], y_data[4:], maxfev=1000000)
print(q_function1(x_data[:5], *p_est1))
print(q_function2(x_data[4:], *p_est2))
print("参数一:",*p_est1)
print("参数二:",*p_est2)
# 绘制图像
plt.plot(
np.arange(0, 64.1, 0.1), q_function1(np.arange(0, 64.1, 0.1), *p_est1), label=r"FIT1"
)
plt.plot(
np.arange(64, 128.1, 0.1), q_function2(np.arange(64, 128.1, 0.1), *p_est2), label=r"FIT2"
)
plt.scatter(x_data, y_data, color="red") # 标记给定的点
# plt.xlabel('x')
# plt.ylabel('y')
plt.title("Function Fit")
plt.legend()
# plt.grid(True)
plt.show()

View File

@ -0,0 +1,36 @@
import matplotlib.pyplot as plt
import numpy as np
# 定义对数函数
def q_function1(vol):
# return -23.65060754864053*((x+508.2130392724084)**0.8433764630986903) + 7.257078620637543 * (x+407.86870598508153) + 1585.6201108739122
# return -58.863374003875954 *((x+12.41481943150274 )**0.9973316187745871 ) +57.92341268595151 * (x+ 13.391132186222036) + -32.92986286030519
return -8.081720684086314 * np.log( vol + 14.579508825070013,)+ 37.65806375944386
def q_function2(vol):
return 0.2721359356095803 * ((vol + 2592.272889454798) ** 1.358571233418649) + -6.313841334963396 * (vol + 2592.272889454798) + 4558.496367823575
# 生成 x 值
x_values = np.linspace(0, 128, 1000)
x_data = np.array([0,16,32,48,64,80,96,112,128])
y_data = np.array([16, 10, 6.75, 4, 2.5, 1.6, 0.8, 0.3, 0])
print(q_function1(x_data))
print(q_function2(x_data))
# 绘制图像
plt.plot(x_values, q_function1(x_values,),label = "fit1")
plt.plot(x_values, q_function2(x_values,),label = "fit2")
plt.scatter(x_data, y_data, color='red') # 标记给定的点
# plt.scatter(x_data, y_data2, color='green') # 标记给定的点
# plt.scatter(x_data, y_data3, color='blue') # 标记给定的点
plt.xlabel('x')
plt.ylabel('y')
plt.title('Function')
plt.legend()
plt.grid(True)
plt.show()