- Notifications
You must be signed in to change notification settings - Fork446
Closed
Labels
Description
Hi, today I was using some step responses and noticed that the.to_pandas() is not actually working.
I managed to workaround it by creating my own function to translate the response into a dataframe.
Example of code not working:
importcontrolasctimportnumpyasnpmodel=ct.rss(states=['x0','x1'],outputs=['y0','y1'],inputs=['u0','u1'],name='My Model')T=np.linspace(0,10,100,endpoint=False)X0=np.zeros(model.nstates)res=ct.step_response(model,T=T,X0=X0,input=0)df=res.to_pandas()
Error:
---------------------------------------------------------------------------ValueErrorTraceback (mostrecentcalllast)CellIn[140],line63T=np.linspace(0,10,100,endpoint=False)4X0=np.zeros(model.nstates)---->6res=ct.step_response(model,T=T,X0=X0,input=0).to_pandas()File~.env/lib/python3.10/site-packages/control/timeresp.py:723,inTimeResponseData.to_pandas(self)719ifself.nstates>0:720data.update(721 {name:self.x[i]fori,nameinenumerate(self.state_labels)})-->723returnpandas.DataFrame(data)File~.env/lib/python3.10/site-packages/pandas/core/frame.py:778,inDataFrame.__init__(self,data,index,columns,dtype,copy)772mgr=self._init_mgr(773data,axes={"index":index,"columns":columns},dtype=dtype,copy=copy774 )776elifisinstance(data,dict):777# GH#38939 de facto copy defaults to False only in non-dict cases-->778mgr=dict_to_mgr(data,index,columns,dtype=dtype,copy=copy,typ=manager)779elifisinstance(data,ma.MaskedArray):780fromnumpy.maimportmrecordsFile~.env/lib/python3.10/site-packages/pandas/core/internals/construction.py:503,indict_to_mgr(data,index,columns,dtype,typ,copy)499else:500# dtype check to exclude e.g. range objects, scalars501arrays= [x.copy()ifhasattr(x,"dtype")elsexforxinarrays]-->503returnarrays_to_mgr(arrays,columns,index,dtype=dtype,typ=typ,consolidate=copy)File~.env/lib/python3.10/site-packages/pandas/core/internals/construction.py:114,inarrays_to_mgr(arrays,columns,index,dtype,verify_integrity,typ,consolidate)111ifverify_integrity:112# figure out the index, if necessary113ifindexisNone:-->114index=_extract_index(arrays)115else:116index=ensure_index(index)File~.env/lib/python3.10/site-packages/pandas/core/internals/construction.py:664,in_extract_index(data)662raw_lengths.append(len(val))663elifisinstance(val,np.ndarray)andval.ndim>1:-->664raiseValueError("Per-column arrays must each be 1-dimensional")666ifnotindexesandnotraw_lengths:667raiseValueError("If using all scalar values, you must pass an index")ValueError:Per-columnarraysmusteachbe1-dimensional
The code I'm using to workaround it is the following:
importmatplotlib.pyplotaspltimportcontrolasctimportnumpyasnpdefstep_response_to_pandas(step_response):returnpd.DataFrame( {'trace_label':np.array([[label]* (len(res.time))forlabelinres.trace_labels]).ravel()}| {'time':res.time.repeat(len(res.trace_labels))}| {label:res.inputs[i].ravel()fori,labelinenumerate(res.input_labels)}| {label:res.outputs[i].ravel()fori,labelinenumerate(res.output_labels)}| {label:res.states[i].ravel()fori,labelinenumerate(res.state_labels)} )defplot_step_response_dataframe(df):grouped=df.groupby(level='trace_label')row_size=1fortrace_label,groupingrouped:fig,axes=plt.subplots(len(group.columns),1,figsize=(6.4,len(group.columns)*row_size),sharex=True)fig.suptitle(f'Trace:{trace_label}',fontsize=16)iflen(group.columns)==1:axes= [axes]forax, (signal_name,signal_data)inzip(axes,group.items()):ax.plot(group.index.get_level_values('time'),signal_data,label=signal_name)ax.grid(True)ax.set_ylabel(signal_name)axes[-1].set_xlabel('Time')plt.tight_layout()plt.show()model=ct.rss(states=['x0','x1'],outputs=['y0','y1'],inputs=['u0','u1'],name='My Model')T=np.linspace(0,10,100,endpoint=False)X0=np.zeros(model.nstates)res=ct.step_response(model,T=T,X0=X0)df=step_response_to_pandas(res)df=df.set_index(['trace_label','time'])plot_step_response_dataframe(df)display(df)
Example of output:
Thanks!


